Errors

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 typeTag of the form error:<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 exposed

In 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 sugar

5.2 TRY ... ELSE

Inline form for guarding a single expression:

TRY 10 / 0 ELSE 0     # → 0

5.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 1

5.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 0

6. 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:

  1. Attempted construct: the interpretation Grid gave the source.
  2. Reason: why that construct cannot be used at this location.
  3. Valid context: where the construct is accepted.
  4. 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 formula

This is a warning, not a blocking error — the model still runs (the override wins, as it does today). To resolve it:

  • Mark the formula default if the override is intentional (the binding is a computed default a rule may override; RESET restores 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/A

Format / 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 0

Or:

A3 = TRY A1 / A2 ELSE 0

Or:

A3 = A2 = 0 THEN 0 ELSE A1 / A2       # explicit guard

8.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/A

If 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)             # TRUE

9.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/A

Use 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