Skip to content

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:

  • name can be edited by any user with access to the model
  • name can be duplicated across families or types
  • name can 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:

  1. Does the parameter exist on this object? (hasValue = true)
  2. 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