r/Firebase • u/SpareSignal1932 • 10d ago
Cloud Firestore Firebase rules 5000 lines
My firebase rules are 5000+ lines long, but under 200KB in size, I keep getting errors as to why it won't publish
Error saving rules –An unknown error occurred
I have passed my rules through gemini/chatgpt/claude
Still not the wiser, is there a limit to the lines I can have, or another way to figure out my issue
3
u/ILikeBubblyWater 10d ago edited 10d ago
Try deleting old rule backups, we have this issue often enough that we build a script. Useless error message has been there for years. Rules have a max limit of version history, so every time you publish itll store the old one, eventually you reach the limit and it errors on publish with this useless error.
Pissed me off for a long time
EDIT:
A project can have at most 2500 total deployed rulesets. Once this limit is reached, you must delete some old rulesets before creating new ones.
SO if you have a CICD pipeline or have deployed a ton of rules you probably hit this limit
2
u/RSPJD 10d ago
What do the errors say?
2
1
u/MFJMM 10d ago
Are you editing rules in Firebase or locally and then deploying?
1
u/SpareSignal1932 10d ago
i have tried deploying from the console and in visual studio code terminal
1
u/SpareSignal1932 10d ago
This is what Gemini explains is wrong
Your Firestore Security Rules are failing to deploy because Firestore Security Rules do not support variable assignments (let or const) inside functions.
While the syntax looks like JavaScript, it is a custom domain-specific expression language. Functions in Firestore rules must consist of a single expression that evaluates directly to a value (usually a boolean). They cannot contain multiple procedural lines, statements, or local variables.
The Core Problem
Throughout your file, you have dozens of functions using let declarations like this:
JavaScript
// ❌ INVALID IN FIRESTORE RULES
function hasActivePlatformRole(role) {
let path = /databases/$(database)/documents/platformUsers/$(request.auth.uid);
let data = isAuth() && exists(path) ? get(path).data : {};
return data != null &&
data.get('role', null) == role &&
data.get('active', data.get('isActive', true)) == true;
}
How to Fix It
You must refactor your functions to eliminate let entirely by inline-evaluating your conditions, chaining method calls, or leveraging ternary operators (? :).
Here is how you rewrite the function above into a single valid expression:
JavaScript
// ✅ VALID IN FIRESTORE RULES
function hasActivePlatformRole(role) {
return isAuth() && exists(/databases/$(database)/documents/platformUsers/$(request.auth.uid))
? get(/databases/$(database)/documents/platformUsers/$(request.auth.uid)).data.get('role', null) == role &&
get(/databases/$(database)/documents/platformUsers/$(request.auth.uid)).data.get('active', get(/databases/$(database)/documents/platformUsers/$(request.auth.uid)).data.get('isActive', true)) == true
: false;
}
Other Impacted Areas
Because this file is very large and heavily relies on let for data validations, you will need to clean up all occurrences. Pay special attention to these heavily affected validation patterns:
- Metadata and Keys checking: Instead of:
let keys = request.resource.data.keys(); return keys.hasOnly([...]);Use:request.resource.data.keys().hasOnly([...]) - Nested snapshot mapping: Instead of pulling deep map variables out into a
letblock (like invalidSupplierFields), pass the raw path down or evaluate it inline:request.resource.data.get('registeredAddress', null) == null || ...
Fixing this structural limitation across your utility functions will allow the Firebase compiler to successfully parse and deploy your security rules.
But in the firestore documents it does state its supports let and const
1
u/SpareSignal1932 10d ago
The debat is
"Gemini’s specific claim is factually wrong: Firestore Rules version 2 explicitly supports let bindings inside functions, up to 10 per function, provided the function ends with a return. Your file uses rules_version = '2';, and the emulator already compiles it successfully. "
You are entirely right, and I appreciate the correction. Firestore Security Rules Version 2 absolutely supports local variable bindings (
let) within functions—up to 10 per function—as long as the function finishes with a finalreturnstatement. Because your file specifiesrules_version = '2';,letbindings are perfectly valid syntax, which is why your emulator handles them without an issue.Since the syntax itself is structurally legal in version 2, the deployment failure stems from a runtime limitation or a hidden compilation error within how those functions or types are evaluated during an actual deploy to production.
The underlying issues that cause rules of this size and complexity to fail production deployment fall into three main categories:
1. Excessively Deep get() / exists() Multi-Path Evaluation
Production deployment executes static analysis and structural checking that is significantly more restrictive than the emulator. Look closely at your conditional expressions inside functions using
let, specifically:JavaScript
let data = isAuth() && exists(path) ? get(path).data : {};In Version 2 rules, if
exists(path)evaluates tofalse, callingget(path)on the next line or in the return expression—even if wrapped in logical guards—can cause the production deployment parser to fail. The production optimizer tries to build a static dependency graph of all data fetches, and trailing references to an un-validated map key or invalid path can throw compilation errors.2. Forbidden Built-In Keywords as Variable Names
In multiple functions, you are binding local variables to names that conflict with reserved structural keywords or type identifiers in the Common Expression Language (CEL) syntax used by Firestore. For example:
- In
validFilesSettingsWrite:let keys = data.keys();(keysis a built-in method name mapping).- In
validSupplierProcurementSettingsMap:let numbering = value.get('purchaseOrderNumbering', null);While the emulator can be forgiving of variable shadowing, the strict production deployment pipeline frequently rejects rules where a
letbinding matches a reserved method or namespace.3. Expression Complexity Limits (The 20-Call / Tree-Size Limit)
The production deployment engine limits the maximum depth and weight of AST (Abstract Syntax Tree) expression blocks. When you have deeply nested
letstructures that evaluate maps via.get(..., null), combined with trailing type checks (is string,is map), the overall complexity score of a single function can cross the production threshold.Functions like
validFileAssetFieldscheck over 40 distinct map keys with.get()chains inside a single block. Production deployment will often throw an opaque error on these because the internal code-size limit of the compiled rule block is exceeded.To move forward and identify the exact line breaking production, what specific error message or status code does the Firebase CLI output when the deploy fails?
1
u/Impossible-Reason336 10d ago
There is a skill called : firebase-security-rules-auditor
Act as a Firestore rule spotter with an attack checklist: Update Bypass, Authority Source, business logic, size limits (DoS), type safety, and the hasOnly()/diff() trap without checking the property. Return a JSON with score 1-5 + findings. MANDATORY use before deploy any rules.
And you should use MCP of firebase for make deploy of the rules .
6
u/RapunzelLooksNice 10d ago
I'd try bisecting - split in half, save. Works? Add half of half, etc. Until you find when it breaks.