[cloud_firestore/permission-denied] in Flutter matchmaking Firestore write #17783
Unanswered
subintoms21
asked this question in
Q&A
Replies: 0 comments
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Uh oh!
There was an error while loading. Please reload this page.
-
I'm building an English learning app using Flutter + Firebase.
The app includes a “Speak to Co-Learner” feature that pairs two users for voice chat using Firestore + Agora.
When users tap “Speak to Co-Learner,” Firestore throws this error:
"⚠️ Error while matching: [cloud_firestore/permission-denied]
The caller does not have permission to execute the specified operation."
The error occurs during creation or transaction update of a document in the call_requests collection, which handles user matchmaking.
🔹 Flutter Code (MatchmakingScreen)
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:firebase_auth/firebase_auth.dart';
import 'package:cloud_functions/cloud_functions.dart';
import 'package:agora_rtc_engine/agora_rtc_engine.dart';
import 'package:permission_handler/permission_handler.dart';
import 'package:intl/intl.dart';
import 'dart:async';
import 'dart:math';
class MatchmakingScreen extends StatefulWidget {
final String? selectedGender;
final String? selectedLevel;
const MatchmakingScreen({super.key, this.selectedGender, this.selectedLevel});
@OverRide
State createState() => _MatchmakingScreenState();
}
class _MatchmakingScreenState extends State {
final _auth = FirebaseAuth.instance;
final _firestore = FirebaseFirestore.instance;
final _functions = FirebaseFunctions.instance; // region hidden for privacy
static const bool debugMode = true;
String? _channelId;
String? _partnerUid;
StreamSubscription<DocumentSnapshot<Map<String, dynamic>>>? _selfSub;
@OverRide
void initState() {
super.initState();
_begin();
}
Future _begin() async {
final mic = await Permission.microphone.request();
if (!mic.isGranted) return;
}
Future _tryClaimOther() async {
final myUid = _auth.currentUser!.uid;
final snapshot = await _firestore.collection('call_requests')
.where('status', isEqualTo: 'waiting')
.limit(10).get();
}
}
🔒 Firestore Security Rules (relevant section)
match /call_requests/{docId} {
function me() { return request.auth.uid; }
allow read: if request.auth != null;
allow create: if request.auth != null &&
request.resource.data.uid == me() &&
request.resource.data.status == "waiting" &&
('createdAt' in request.resource.data);
allow update: if request.auth != null && (
resource.data.uid == me()
||
(
resource.data.status == "waiting" &&
request.resource.data.status == "matched" &&
request.resource.data.partnerUid == me() &&
(
!('channelId' in request.resource.data) || request.resource.data.channelId is string
) &&
(
!('matchedAt' in request.resource.data) || request.resource.data.matchedAt is timestamp
)
)
||
(
resource.data.status == "matched" &&
(resource.data.uid == me() || resource.data.partnerUid == me())
)
);
allow delete: if request.auth != null &&
(resource.data.uid == me() || resource.data.partnerUid == me());
}
Tried So Far
Tested .set() with and without merge:true
Verified Firestore rules in Rules Playground → “Allow”
Confirmed user is authenticated via FirebaseAuth
Verified uid matches authenticated user
Tried removing ttlAt and serverTimestamp() (same result)
Works on emulator, but fails on real device (production)
🔹 Expected Behavior
Authenticated users should be able to create or update their own matchmaking document in /call_requests without permission errors.
Environment
Additional Notes
All Firestore rules deploy successfully.
Other collections (users, grammar_lessons, etc.) work fine.
Only call_requests create/update fails with permission-denied.
The issue may be related to Firestore evaluating .set(merge:true) as an update instead of a create operation.
Question:
Can the maintainers confirm if Firestore’s merge:true behavior requires different rule handling,
or if a transaction write like the one above fails rule evaluation due to timing/order?
If required, I can share the complete matchmaking_screen.dart and full Firestore rules file.



Beta Was this translation helpful? Give feedback.
All reactions