Errors And Diagnostics
Errors And Diagnostics
In Grid, errors are first-class typed values. They flow through formulas just like numbers and strings, and you handle them with explicit error-handling functions and operators.
This doc lists every error code, when it fires, what it means, and how to recover.
1. The Error Value
Every error has:
- A code like
VALUE,N/A,DIV/0,REF. - A message explaining the cause.
- A
typeTagof the formerror:<code>.
In source code, 9 error literals are writable using the Excel-compatible spelling:
#N/A #DIV/0! #VALUE! #REF!
#NAME? #NULL! #NUM! #CALC! #SPILL!You can write any of these anywhere a value is expected:
A1 = #N/A
B1 = IF(missing, #N/A, value)Two additional error codes are Grid-generated only — the parser rejects them as literals because they describe structural problems that source code shouldn't claim to produce:
| Code | Why no literal |
|---|---|
#TYPE! |
Generated when a type-tag check fails on an assignment |
#CIRCULAR_REF! |
Generated when the dependency graph contains a cycle and iterative calculation is off |
If you need to construct one of these in a formula, use a function:
A1 = IF(condition, errorValue("TYPE", "..."), normalValue) # not currently exposedIn v1, #TYPE! and #CIRCULAR_REF! are values you read, not values you write.
2. Every Error Code
| Code | Literal | Fires when | Recover with |
|---|---|---|---|
N/A |
#N/A |
A lookup found no match; a function explicitly signals "no value" | IFNA, IFERROR, DEFAULT, ?= |
DIV/0 |
#DIV/0! |
Division by zero | IFERROR, TRY ... ELSE, defensive predicate |
VALUE |
#VALUE! |
Wrong argument shape, incompatible kinds, parse failure inside a typed literal | IFERROR, WITH ... ELSE |
REF |
#REF! |
A reference is invalid or out of bounds; spill anchor is wrong; OFFSET / INDIRECT resolves to nothing |
Re-check addresses; structural fix |
NAME |
#NAME? |
Unknown function name or unknown named argument | Check spelling; check getFunctionDefinition |
NULL |
#NULL! |
Intersection of ranges is empty | Re-check range syntax |
NUM |
#NUM! |
Numeric argument out of domain (e.g. SQRT(-1)); singular matrix; convergence failure |
Validate inputs; choose different algorithm |
CALC |
#CALC! |
Iterative method failed (e.g. ROOT did not converge); empty FILTER result |
Tune tolerances; provide if_empty argument |
SPILL |
#SPILL! |
An array-returning formula's spill rectangle hits a populated cell | Move the formula or clear the obstructing cell |
TYPE |
#TYPE! |
A typed assignment receives a value incompatible with its type tag, or a structured predicate field violates its declared contract | Match the kind to the type-tag/predicate-field contract, or fix the declaration |
CIRCULAR_REF |
#CIRCULAR_REF! |
A cyclic dependency was detected and iterative calculation is off | Break the cycle or enable iterative calculation for convergent cycles |
Structured predicate fields are always enforced contracts. Unlike an ordinary
type overlay under loose, predicate reviewed(score: number) cannot accept
:reviewed("high"): field access and presence both surface #TYPE! so an
invalid payload cannot be mistaken for a valid present predicate. Unknown
predicate fields, wrong payload arity, and incomplete PREDICATES(x) views are
compile-time diagnostics rather than error values. A many declaration must
include a non-empty by (...) list of distinct declared fields. Adds require
the complete payload;
keyed removals require only the identity values, in many by order. Duplicate
identity fields, unknown identity fields, and the wrong keyed-removal arity are
also compile-time diagnostics.
Additional external-call failure codes may appear when a background value cannot be refreshed:
| Code | Meaning |
|---|---|
TIMEOUT |
The external call exceeded its timeout |
EXTERNAL |
The external provider or adapter raised an exception |
STALE_FALLBACK |
A fresh value failed, so Grid used the last cached value |
3. Error Propagation
Errors short-circuit. A function that receives an error argument returns that error unchanged unless it is one of the explicit error-handling functions or a structural predicate that is defined to inspect error identity.
A1 = #N/A
A2 = A1 + 5 # → #N/A (propagated)
A3 = SUM(A1, 1, 2) # → #N/A (propagated)
A4 = IFERROR(A1, 0) # → 0 (handled)
A5 = NA() IN [NA()] # → TRUE (structural error-code comparison)
A6 = NA() IN [#VALUE!] # → FALSE (different error codes)The first error encountered in a positional argument list wins. Named
arguments don't change this rule for ordinary evaluation. IN/HAS,
SUBSET/SUPERSET, OVERLAPS, and ordered CONTAINS are the collection
relation exception: an error used as a member or pattern element is compared by
error code, and its diagnostic message is ignored. They do not coerce the error
into a normal scalar. Error-kind MATCH arms and the functions below are the
other explicit inspection/handling forms.
4. Error-Handling Functions
These functions are designed to consume errors:
| Function | Behavior |
|---|---|
IFERROR(value, fallback) |
If value is any error, return fallback; else return value |
IFNA(value, fallback) |
Like IFERROR but only catches #N/A |
ISERROR(value) |
TRUE if value is any error |
ISERR(value) |
TRUE if value is an error other than #N/A |
ISNA(value) |
TRUE if value is #N/A |
ERROR.TYPE(value) |
Numeric code matching Excel: 1=#NULL!, 2=#DIV/0!, 3=#VALUE!, 4=#REF!, 5=#NAME?, 6=#NUM!, 7=#N/A |
5. Error-Handling Operators And Clauses
5.1 DEFAULT / ??
The cheapest fallback. Returns the right-hand side if the left is
BLANK or any error.
A1 DEFAULT 0 # canonical
A1 ?? 0 # accepted sugar5.2 TRY ... ELSE
Inline form for guarding a single expression:
TRY 10 / 0 ELSE 0 # → 05.3 WITH ... THEN ... ELSE
For multi-step external chains where any step might fail:
WITH data = HTTP_JSON(url), users = data.results
THEN users[1].name ELSE "unavailable"If HTTP_JSON fails, or data.results errors, or the then
expression errors, the ELSE value is returned.
The bindings list can span lines (each , at end-of-line), but the
final THEN <expr> ELSE <fallback> must be on a single line.
5.4 ASSERT Clause
Short-circuit a value through a predicate:
value ASSERT value > 0 # #VALUE! if assertion fails
value ASSERT value > 0 ELSE #N/A # custom error
score ASSERT score BETWEEN 0 AND 15.5 ?= (Conditional Eager Assignment)
If the right-hand side is any error, skip the assignment — preserve the previous value:
A3 = 0
A3 ?= MAYBE_FAIL() # if MAYBE_FAIL() errors, A3 stays at 06. Validation Diagnostics
Some errors are model diagnostics rather than binding values. Grid reports them while parsing or validating the model.
| Diagnostic | Cause |
|---|---|
Parse error at line N |
Source could not be parsed |
Cyclic reference detected |
Same condition as #CIRCULAR_REF!, but reported at build |
Unknown function FOO |
The model references a function not in the registry |
Range target spans more than X cells |
Configurable cell-count limit on range broadcasts |
A model with error-level validation diagnostics will not run. Fix all of them first.
6.1 Contextual grammar diagnostics
Some Grid forms are meaningful only in a particular grammatical context. A diagnostic for one of these forms is part of the language contract, not merely a parser failure. It identifies four things:
- Attempted construct: the interpretation Grid gave the source.
- Reason: why that construct cannot be used at this location.
- Valid context: where the construct is accepted.
- Canonical rewrite: a source form that expresses the supported shape.
For example, balance += payment at top level is recognized as arithmetic
compound assignment. Grid explains that a top-level declaration has no prior
value source, names a reactive rule action as the valid context, and shows the
statement inside a WHEN ... THEN ... END rule. It does not report an
unqualified "unexpected token" error.
Stable diagnostic codes let editors and agents act on the same contract:
| Code | Attempted construct |
|---|---|
GRID_TOP_LEVEL_COMPOUND_ASSIGNMENT |
Arithmetic compound assignment outside a rule action |
GRID_ASSIGNMENT_SCHEDULE_OPERATOR |
A schedule modifier attached to a non-eager assignment |
GRID_INPUT_DECLARATION_SHAPE |
An input written with mutation, laziness, conditional preservation, or a schedule |
GRID_STATE_DECLARATION_SHAPE |
A state declaration written with a non-eager operator or schedule |
GRID_RULE_ACTION_ASSIGNMENT_OPERATOR |
A rule target without an assignment operator |
GRID_RULE_ACTION_LAZY_ASSIGNMENT |
Lazy assignment inside an executing rule action |
GRID_PREDICATE_BUILTIN_LAW |
A bare law uses a name shared with a qualitative family; add the canonical predicate introducer to select an open logical law |
GRID_LOGICAL_MODAL_ATOM_REQUIRED |
A top-level logical modality or a general MAY/CANNOT/EVIDENCE query contains a compound proposition; query one ground atom instead |
GRID_PREDICATE_LAW_ORDER |
A same-named open law appears after a clause already parsed with its built-in qualitative meaning |
6.2 Static-analysis diagnostics (warnings, strict-promoted)
Compile-time analyses emit these without running the model. All are
warnings under the default mode; the first three become hard compile
errors under strict / dimensions strict (see
reference §5.4):
| Code | Meaning |
|---|---|
GRID_DIMENSION_MISMATCH |
Incompatible units/currencies in one expression |
GRID_MATRIX_SHAPE_MISMATCH |
Provably impossible matrix shapes (MMULT inner dimensions, non-square MINVERSE/MDETERM, MUNIT size, SUMPRODUCT shape drift) |
GRID_VALIDATE_UNSATISFIABLE |
A VALIDATE assertion the formula can never satisfy — or an input default violating its own write contract |
GRID_VALIDATE_UNVERIFIED |
A VALIDATE assertion on a computed cell that interval analysis cannot decide; nothing checks it at runtime |
Anything the analyses cannot prove stays silent — unknown shapes and unbounded ranges never diagnose.
6.3 GRID_MIXED_OWNERSHIP (warning)
A binding has a plain formula and a set-mode rule action targeting it.
The rule's write installs a sticky override that shadows the formula — the
formula's value never surfaces once the rule first fires, and WHY would
otherwise trace a formula whose value is dead.
B1 = A1 * 2 # formula
WHEN tick THEN B1 = 99 END # ⚠ GRID_MIXED_OWNERSHIP: the rule shadows B1's formulaThis is a warning, not a blocking error — the model still runs (the override wins, as it does today). To resolve it:
- Mark the formula
defaultif the override is intentional (the binding is a computed default a rule may override;RESETrestores it), or - move the rule off the binding if the formula should own it.
RESET and CLEAR actions never trigger the warning — they manage the
override layer without colliding with the base op.
6.4 Symbolic-mathematics diagnostics
Symbolic mathematics fails closed at three boundaries. Source diagnostics
reject an invalid declaration or lift before the model compiles; authority and
compiled-model diagnostics reject unauthorized or malformed resident
operations; mathematical operation records use :not_applicable, :limit, or
:invalid without publishing an uncertified partial expression.
Common source diagnostics are:
| Code | Meaning |
|---|---|
GRID_SYMBOL_AUTHORITY |
The compiling model has no stable, portable module authority |
GRID_SYMBOL_CELL_NAME |
A symbolic variable was declared with a cell-address spelling |
GRID_SYMBOL_DUPLICATE |
The same symbolic variable is declared more than once |
GRID_SYMBOL_MUTABLE_COLLISION |
An input, state, default, or other mutable target collides with an immutable symbolic variable |
GRID_SYMBOL_RULE_TARGET |
A rule attempts to mutate an immutable symbolic variable |
GRID_SYMBOL_IMPORT_COLLISION |
Local and imported symbolic identities collide |
GRID_SYMBOL_DECLARATION_TAIL |
A symbol declaration contains unsupported trailing syntax |
The closed runtime family uses these stable diagnostic categories:
| Code | Meaning |
|---|---|
GRID_SYMBOLIC_AUTHORITY_MISSING / GRID_SYMBOLIC_AUTHORITY_MISMATCH |
The module did not carry the exact shipped math.expression authority requested by its symbolic opcodes |
GRID_SYMBOLIC_AUTHORITY_ORPHANED / GRID_SYMBOLIC_AUTHORITY_INVALID |
Mathematical authority metadata exists without symbolic use, is malformed, or does not satisfy the shipped authority shape |
GRID_SYMBOLIC_BUILTIN_UNKNOWN / GRID_SYMBOLIC_BUILTIN_NONCANONICAL |
The compiled model names an unregistered symbolic builtin or does not use its canonical closed-registry spelling |
GRID_SYMBOLIC_CONSTRUCTION_INVALID |
A symbolic construction opcode has malformed attributes, operands, or constructor metadata |
GRID_SYMBOLIC_ASSUMPTION_INVALID |
An assumptions value is malformed or no longer has its canonical evidence ordering, consistency flag, and fingerprint |
GRID_SYMBOLIC_TYPE / GRID_SYMBOLIC_LIFT_TYPE |
A value is not a mathematical Tree or cannot cross the exact symbolic coefficient boundary |
GRID_SYMBOLIC_CALL_TYPE |
A runtime-polymorphic mathematical Tree reached an ordinary-only function argument; use an explicit Tree-aware or SYMBOLIC.* consumer |
GRID_SYMBOLIC_RATIONAL_TYPE |
SYMBOLIC.RATIONAL received a numerator or denominator that is not an exact integer expression |
GRID_SYMBOLIC_VARIABLE_INVALID |
A symbolic variable authority or name violates the bounded, nonempty, control-free identity contract |
GRID_SYMBOLIC_TRUTHINESS |
A symbolic expression or relation reached an implicit Boolean position instead of being decided or evaluated explicitly |
GRID_SYMBOLIC_SELECTOR_TYPE |
COLLECT, APART, D, SOLVE, or SUBSTITUTION received something other than a symbolic_variable value |
GRID_SYMBOLIC_SUBSTITUTION_TYPE |
A substitution record is malformed or does not contain a variable and mathematical replacement |
GRID_SYMBOLIC_DOMAIN_TYPE |
DOMAIN or SOLVE received an unsupported or non-symbolic domain selector |
GRID_SYMBOLIC_PROPOSITION_TYPE / GRID_SYMBOLIC_RELATION_TYPE |
An assumptions, decision, or solve operation received the wrong proposition kind |
GRID_SYMBOLIC_ARITY / GRID_SYMBOLIC_BUILTIN_ARITY / GRID_SYMBOLIC_DISPATCH_ARITY |
A public or runtime-polymorphic SYMBOLIC.* call has the wrong argument count |
GRID_SYMBOLIC_DISPATCH_LITERAL_AUTHORITY |
Runtime-polymorphic dispatch would apply direct-literal exactness to a reference or other value that no longer has that source authority |
GRID_SYMBOLIC_NOT_POLYNOMIAL |
An exact polynomial/rational algorithm was asked to consume a value outside its admitted domain |
GRID_SYMBOLIC_NOT_DIFFERENTIABLE |
The requested derivative is outside the closed admitted function or branch contract |
GRID_SYMBOLIC_DIV_ZERO |
Exact rational construction or algebra encountered a proved zero denominator |
GRID_SYMBOLIC_PRECISION_INVALID / GRID_SYMBOLIC_ROUNDING_INVALID |
SYMBOLIC.APPROXIMATE received an invalid precision or rounding policy |
GRID_SYMBOLIC_APPROX_AUTHORITY |
Evaluation would mix incompatible precision or rounding authorities, or route an arbitrary-precision value through the fixed machine-real evaluator |
GRID_SYMBOLIC_APPROX_DOMAIN |
Machine-real evaluation received or produced NaN or infinity outside the admitted finite domain |
GRID_SYMBOLIC_APPROX_NOT_APPLICABLE |
A value is not ground or has no admitted certified approximation |
GRID_SYMBOLIC_LIMIT, GRID_SYMBOLIC_WORK_LIMIT, GRID_SYMBOLIC_PRECISION_LIMIT, GRID_SYMBOLIC_LITERAL_LIMIT, GRID_SYMBOLIC_ASSUMPTION_LIMIT |
A declared hard resource bound was reached before publication |
GRID_SYMBOLIC_PUBLICATION_LIMIT / GRID_SYMBOLIC_DECODE_LIMIT |
A mathematical expression exceeded a hard node, depth, degree, or byte bound while being validated for publication or decoded for execution |
GRID_SYMBOLIC_RENDER_LIMIT_INVALID |
A requested bounded-render byte, node, or depth limit is zero or outside the runtime's hard admissible range |
GRID_SYMBOLIC_VALUE_INVALID / GRID_SYMBOLIC_LITERAL_INVALID |
A persisted or constructed mathematical value is noncanonical or malformed |
GRID_SYMBOLIC_DERIVATION_INVALID |
A symbolic result derivation is malformed, noncanonical, or does not bind its declared operation and mathematical structures |
GRID_SYMBOLIC_DERIVATION_LIMIT |
A symbolic result derivation exceeded its hard certificate byte, condition, Tree, or work representation bound |
GRID_SYMBOLIC_DERIVATION_REPLAY_MISMATCH |
Input-bearing replay disagreed with the certificate-bound operation, version, input, output, conditions, or work coordinate |
GRID_SYMBOLIC_DISPATCH_ATTRS_INVALID |
Versioned compiled symbolic-dispatch attributes are malformed, unsupported, or inconsistent with their operands |
GRID_SYMBOLIC_LIR_INVALID / GRID_SYMBOLIC_OPERATION_INVALID |
A symbolic opcode, operation tag, or versioned attribute combination survived to execution in an invalid shape |
GRID_SYMBOLIC_ALGEBRA |
The exact algebra kernel rejected an internal invariant or an algebraic case without a more specific public category |
An expression-operation record with status = :limit or :invalid has
expression = BLANK unless the operation explicitly defines a certified
prefix. SYMBOLIC.SOLVE similarly keeps :none, :unknown, and :limit
distinct. Do not recover from these states by parsing display text; inspect the
status and conditions, reduce the problem or adjust the authored bound, and
rerun the typed operation. See
symbolic-mathematics.md.
7. The Error Type Tag
Every error value carries typeTag = "error:<code>". You can match on
it explicitly:
A1 IS ERROR # TRUE for any error
ISERR(A1) # TRUE for any error other than #N/AFormat / display:
TEXT(A1, "") # error string e.g. "#DIV/0!"8. Worked Examples
8.1 Defensive Division
A1 = numerator
A2 = denominator
A3 = IFERROR(A1 / A2, 0) # → 0 if A2 is 0Or:
A3 = TRY A1 / A2 ELSE 0Or:
A3 = A2 = 0 THEN 0 ELSE A1 / A2 # explicit guard8.2 Lookup With Fallback
A1 = VLOOKUP("Alice", users, 2, FALSE) DEFAULT "n/a"
A2 = IFNA(VLOOKUP("Bob", users, 2, FALSE), "n/a")8.3 External Call With Fallback
B1 = FX_RATE("EUR", "USD")
B2 is currency = ROUND(amount * (B1 DEFAULT 1.08), 2)While B1 is queued or failed, B2 uses the fallback rate.
8.4 Multi-Step Chain
result = WITH data = HTTP_JSON(url), first = data.results[1], name = first.name
THEN name ELSE "unknown"8.5 Validating An Input
A1 is percentage = input ASSERT input BETWEEN 0 AND 1 ELSE #VALUE!8.6 Detecting Specific Errors
status = IF(ISNA(A1), "missing",
IF(ISERR(A1), "error",
IF(ISBLANK(A1), "empty", "ok")))9. Common Mistakes
9.1 Forgetting Errors Propagate
A1 = SUM(B1:B10) # B5 = #N/A → A1 = #N/AIf B1:B10 may contain errors, filter first:
A1 = SUM(IFERROR(B1:B10, 0))Or use AGGREGATE with the "ignore errors" mode:
A1 = AGGREGATE(9, 6, B1:B10)9.2 Confusing Blank With Empty String
A1 = "" # empty string, not blank
A2 = BLANK # blank
ISBLANK(A1) # FALSE
ISBLANK(A2) # TRUE9.3 Catching #N/A With ISERROR
ISERROR(#N/A) # TRUE — catches everything
ISERR(#N/A) # FALSE — explicitly excludes #N/A
ISNA(#N/A) # TRUE — catches only #N/AUse ISERR if you want "errors but not missing-values".
9.4 Treating External Pending States As Errors
A binding whose external call is queued or running is not an
error. It carries a previous cached value (or BLANK) with a stale
status. Use external-function status, not ISERROR, to distinguish pending
work from failed work.
9.5 Using ?= On A Target That Doesn't Exist Yet
A1 ?= MAYBE_FAIL() # if MAYBE_FAIL fails, A1 has no previous value to preserve → A1 stays uninitialized (BLANK)?= only protects against overwriting; it doesn't conjure a value.
10. See Also
reference.mdfor error literal spellings.functions.mdforIFERROR,IFNA, etc.assignments.mdfor?=.external-functions.mdfor status-vs-error distinction.