Defensive Rule Writing
Revit models are not clean. Parameters get added mid-project, bindings are incomplete, users rename things, and some elements are never touched after placement.
A rule that assumes clean data will silently miss errors — or crash on data it never expected.
This page describes the mental model for writing rules that are reliable in real conditions.
Assume parameters may not exist
Shared parameters are not guaranteed to be present on every object. A parameter might be bound to doors but not to windows. It might have been added after some elements were placed.
In DAQS JSON, this shows up in two different ways:
/* Parameter exists but has no value */
"p_8fe8f5ce-4979-4679-b5e0-ccfb362b9059": {
"hasValue": false,
"value": null
}
/* Parameter not present at all — key is missing from values */
When a parameter key is missing entirely, JSONata returns undefined when you try to read it — not null, not false. This is a third state that most validators do not expect.
Practical consequence: validate hasValue separately from value. A rule that checks value != null will not catch elements where the key is missing entirely.
Never trust name for linking
Both id and name are identity fields, but only id is stable:
namecan be edited by any user with access to the modelnamecan be duplicated across families or typesnamecan differ between localised Revit installations
When linking objects — finding a FamilySymbol from an instance, looking up a Parameter by identifier — always use id or GUID:
/* Safe — id never changes unless element is deleted */
$[type = "FamilySymbol" and id in $doorSymbolIds]
/* Fragile — any user can rename this */
$[type = "FamilySymbol" and name = "1018x2387"]
The same principle applies to parameters. A shared parameter's GUID is permanent. Its name can be renamed in the project without breaking bindings.
Check existence before checking value
When writing a rule that validates a shared parameter, you often need two separate rules:
- Does the parameter exist on this object? (
hasValue = true) - Does the parameter have a correct value? (
value != null and value != "")
Combining both checks into one rule hides the real problem. If an element fails because the parameter was never bound, that is a configuration error — not a data quality error. Treating them the same makes it harder to diagnose and fix.
Handle null explicitly
Some fields in Revit have three meaningful states, not two:
| State | JSON | Meaning |
|---|---|---|
| Value present | "value": "EI 30" |
Data entered |
| Value cleared | "value": null |
Was entered, now removed |
| Never bound | key missing | Parameter not on this object type |
A rule that checks value = "EI 30" will fail for both null and missing — correctly — but will report the same error for two very different root causes.
Where the distinction matters, use hasValue to separate them.
Assume bindings are incomplete
It is common for a shared parameter to be bound to some types but not all. This is not always a mistake — some parameters are type-specific.
When writing a rule that applies only to elements where a parameter should be present, use the scope condition to restrict the rule. A well-scoped filter prevents false positives on elements where the absence is intentional.
Example: fire rating is only required for door types with Assembly Code 32.31. If you validate fire rating on all door types, you will flag types that were never expected to have it.
Always test with elements that should fail
A rule that never produces errors is not necessarily correct. It may be filtering out exactly the elements it should be catching.
Before trusting a rule, verify it against data that contains known failures: - An instance with a missing mark - A type with an empty assembly code - A parameter that was never bound
If the rule reports 0 errors on data you know is wrong, the filter is the problem. See Filtering vs Validation.
Summary
| Assumption | Why it matters |
|---|---|
| Parameters may not exist | Missing keys return undefined, not null |
name is not stable |
Use id and GUID for linking |
| Existence ≠ value | Check hasValue and value separately when needed |
| Bindings may be partial | Scope your rule to only the objects where the parameter applies |
| Rules can silently pass | Always test with data that should fail |