Repository navigation
Firestore Emulator v1.22.0 reports ambiguous evaluation errors for valid false Rules predicates #11283
Description
firebase-tools: 15.30.2
Platform: Windows 11 Pro
- Firestore Emulator: v1.22.0
- Java: 21.0.11 LTS
- Node.js: 22.22.0
- Firebase project: "demo-firestore-rules-diagnostic" (local emulators only)
- Requests: Node.js built-in "fetch" to the local Firestore REST endpoint
- Authentication: synthetic local Auth emulator account
- Concurrency: sequential requests
[REQUIRED] Test case
The Firestore Emulator returns HTTP 403 / "PERMISSION_DENIED" for five deliberately forbidden document creations.
However, three valid false predicates produce generic "evaluation error" diagnostics, without any explicit cause in Rules coverage.
Minimal predicates:
- Literal false: "allow create: if false;"
- Absent document: "allow create: if exists(/databases/$(database)/documents/fixtures/intentionally-absent);"
- Existing map value: "allow create: if request.resource.data.get('label', '') == 'never';"
- Missing key: "allow create: if request.resource.data.keys().hasAny(['requiredFlag']);"
- Deliberately invalid property: "allow create: if request.resource.data.requiredFlag == true;"
Each predicate has its own isolated collection match.
Every create request contains the synthetic document:
"{"label":"synthetic"}"
The third predicate accesses an existing key and compares its value against a different string. The fifth predicate deliberately accesses a missing property as a control case.
[REQUIRED] Steps to reproduce
- Place "firebase.json", "firestore.rules", and "reproduce.mjs" from the minimal reproducer in one directory.
- Confirm that local ports 18120 and 19120 are available.
- Run the following PowerShell command from that directory:
"firebase emulators:exec --config firebase.json --project demo-firestore-rules-diagnostic --only auth,firestore "node reproduce.mjs""
- Inspect the generated "results.json" and Rules coverage.
- Compare the five request diagnostics.
No Firebase login, cloud project, production credentials, npm package installation, or imported customer data is required.
[REQUIRED] Expected behavior
All five requests should remain denied.
However, authorization predicates that legitimately evaluate to false should be distinguishable from genuine evaluation failures.
For example, an absent-document "exists()" result, a false "Map.get()" comparison, and a false "keys().hasAny()" result should not be indistinguishable from an actual evaluator exception.
Ideally, the response or Rules coverage should provide structured information identifying whether the final outcome was an intentional false predicate or an evaluation failure.
[REQUIRED] Actual behavior
All five requests return HTTP 403 / "PERMISSION_DENIED", but their diagnostics differ:
Predicate| Result
Literal "false"| Clean denial
"exists()" absent| Generic evaluation error
Existing "Map.get()" comparison false| Generic evaluation error
"keys().hasAny()" false| Generic evaluation error
Invalid missing property| Evaluation error with explicit cause
Reproducer results:
- 5/5 expected HTTP outcomes matched.
- Process exit code: 0.
- Three generic evaluation-error diagnostics.
- No expression-limit warnings.
- Raw Rules coverage contains no explanatory "causeMessage" for the three generic cases.
- Deliberately invalid property access correctly produces: "Property requiredFlag is undefined on object."
This creates ambiguity for negative authorization tests: checking only for "PERMISSION_DENIED" may hide a genuine Rules evaluation failure, while rejecting every generic evaluation error also rejects the valid false-predicate cases demonstrated here.
This report concerns the emulator's diagnostic precision. It does not claim that an application's security rules are correct simply because a request was denied.
Related reports:
- Rules using resource.data run twice in Firestore emulator #6252
- Firestore Rules emulator: denial message concatenates every match block's evaluation, and "Variable is not bound in path template." omits the variable name #11239
- Firestore emulator rules get() intermittently fails as PERMISSION_DENIED after transaction lock timeout #10518
Questions for maintainers:
- Is this generic diagnostic expected for valid false document/map predicates?
- Can the emulator distinguish an intentional false result from a genuine evaluator exception?
- Is there a supported debug flag or structured coverage field that exposes the actual cause?
- Could this result from multiple internal evaluations being combined into one denial message?
A minimal synthetic reproducer and captured diagnostics are available for investigation.
Activity
sharanbingi commentedon Oct 17, 2026
Additional evidence for #11283: the same ambiguous denial diagnostic occurs on an update comparing an existing immutable string field, in both Firestore emulator 1.20.2 and 1.22.0. This extends the reported create/false-map-predicate examples; it does not establish a common internal cause.
Environment: Windows, Java OpenJDK25.0.3 (build25.0.3+-15898627-b508.16), rules-unit-testing3.0.4, Firebase JS SDK10.14.1 / Firestore SDK4.7.3. Installed CLI15.30.1; JARs launched directly. Synthetic demo project only; no production comparison.
Exact tested guarded rule (single match, no recursive overlap):
Synthetic authenticated UID
alpha_sales_a; trusted/users/alpha_sales_a:{ "uid": "alpha_sales_a", "role": "SALES_USER", "dealershipId": "dealership_alpha", "storeId": "STORE_A", "active": true }Existing
/dealerships/dealership_alpha/sales/sale_seed_001:{ "saleId": "sale_seed_001", "dealershipId": "dealership_alpha", "storeId": "STORE_A", "customerId": "cust_001", "vehicleId": "veh_001", "loanId": "loan_seed_001", "paymentType": "CASH", "finalSaleAmountPaise": 8500000, "amountReceivedPaise": 8500000, "outstandingAmountPaise": 0, "paymentStatus": "COMPLETED", "notes": "Initial seed notes" }Each operation independently reseeds this fixture. Both old and proposed saleId are present strings. No transforms; authenticated SDK
.update().{notes:'metadata-positive',updatedAt:2}{saleId:'sale_seed_001'}{saleId:'forged_sale_id'}Both guarded SDK responses (
code: permission-denied) and emulator stderr contain exactly:The SDK prefixes it with
7 PERMISSION_DENIED:. No version-dependent wording difference or expression-limit diagnostic was observed. L15 identifies the allow entrypoint, not a proven internal failing expression. The equality-free control is intentionally unsafe and is not a fix. No missing-field control was added to this reproduction.Loaded-rules evidence on both versions: observed local
:securityRulesPUT, HTTP200, actual guarded payload SHA256ED0306B445E8AFA8DD49348C2AC028AB7A6CACBD88605B0C0DD0935FB5C52B4A. The observer checks the uploaded bytes, demo project and selected local port. Rule payloads, coverage, SDK errors, mutation control and both positive-control records are attached. Coverage is cumulative per predicate; it does not prove the internal cause. Post-read deep equality verified unchanged rejected documents and exact successful updates; raw after maps were not separately serialized.Both guarded runs exit1 under the preserved strict diagnostic assertion, despite correct functional denial. Both unsafe-control runs also exit1; a granted mutation is never counted as security acceptance. Portable harness copies only parameterize the port and have not been rerun after packaging; exact executed predicates/fixtures and result evidence are retained.
Could maintainers confirm whether this false immutable-field comparison is another expected instance of the diagnostic ambiguity described here, and which supported diagnostic field distinguishes it from a genuine evaluator exception? Internal cause remains unverified; no production parity or broader rule correctness is claimed.
seryxdev commentedon Oct 17, 2026
Thank you for the additional reproduction and detailed comparison between Firestore Emulator versions 1.20.2 and 1.22.0.
This is particularly relevant to our testing, where we are observing similar ambiguous
evaluation errordiagnostics during security-rule denial tests.In our isolated Firebase Emulator environment, we recorded:
Our strict diagnostic checks remain blocked because a
PERMISSION_DENIEDresponse containingevaluation errorcannot automatically be treated as a clean, intentional denial.The new immutable-field reproduction suggests that some of these diagnostics may occur even when the intended authorization behavior is preserved. However, we cannot assume the same root cause without further verification.
Could the Firebase team clarify:
false, or does it indicate an evaluator defect?We are deliberately keeping our strict security assertions enabled and are not treating HTTP 403 responses alone as sufficient evidence of Rules correctness.
Thank you for investigating this issue.
masonbickers commentedon Oct 18, 2026
Additional isolated GET reproduction on macOS arm64, with Firebase CLI 15.34.0 / Firestore emulator 1.22.0, Temurin Java 21.0.12.1, Node 24.19.0,
firebase@11.10.0and@firebase/rules-unit-testing@4.0.1.Only a local
demo-project, synthetic authentication contexts and two boolean-only user documents are used. All target documents are intentionally absent. There are no production credentials, customer data or application rules in this example. The four predicate forms below each compare a present boolean field on an existing user document; the missing-property case is deliberately broken as an alert control.Observed in a fresh local run:
denieduser (allowed: false)alloweduser (allowed: true)evaluation error ... false for 'get'Property missingFlag is undefined on object.12/12 expected authorization/error-control assertions pass; six SDK responses still contain evaluation diagnostics (four generic, two genuine faults). This is not clean diagnostic acceptance. The separate diagnostic smoke check below exits 1. Our required application diagnostic checks remain unchanged and failing; we are not treating a denial or assertion pass as proof that a diagnostic is harmless. This reproduction does not establish that every application diagnostic has this cause, or make a production-parity claim.
To reproduce in a new disposable directory, save the following four files. Install the listed versions (the executed run reused an existing installation of those exact versions; a fresh npm install was not separately tested):
npm init -y npm install --save-exact firebase@11.10.0 @firebase/rules-unit-testing@4.0.1 firebase-tools@15.34.0 npx firebase emulators:exec --only firestore --project demo-firestore-diagnostics --config firebase.json "node --test --test-concurrency=1 reproduce.mjs" node strict.mjsThe last command is expected to exit 1 while these diagnostics remain. No Firebase login is required. Use free local ports as configured below.
firebase.json:{ "firestore": { "rules": "firestore.rules" }, "emulators": { "firestore": { "host": "127.0.0.1", "port": 18128 }, "hub": { "host": "127.0.0.1", "port": 18129 }, "logging": { "host": "127.0.0.1", "port": 18130 }, "ui": { "enabled": false }, "singleProjectMode": true } }firestore.rules:reproduce.mjs:strict.mjs:Could a maintainer advise on a supported correction or supported structured diagnostic field that distinguishes an intentional false result from a genuine evaluation exception, while preserving all genuine-error alerts? If this is known behavior, which emulator/CLI version, documented setting or per-request diagnostic field should we test? If it needs a runtime fix, is there a tracking change or corrected build available for validation?
We are not looking to filter messages, substitute weaker rules or waive negative authorization checks. No such workaround has been applied. The full raw SDK messages are retained in the generated
results.jsonfor this synthetic example.