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.

Symbol requests also validate spreadsheet bounds. Letter-and-number names such as MdToM2 can be interpreted as addresses regardless of case. An out-of-range address error explains that ambiguity, states the supported bounds, and suggests an underscore such as Permeability_m2. This is a host symbol diagnostic, not a new formula error code. Valid A1/R1C1 references keep their meaning, and source names are not automatically rewritten.


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

CURVE_FIT and NSOLVE retain VALUE for malformed arguments and CALC for numerical failure, with a message identifying the function, cause, and recovery guidance. An underdetermined fit explains that there are more free parameters than observations. Initial-evaluation failure, singular numerical work, and nonconvergence have distinct explanations. See the chemistry workflow guide.

CURVE_FIT and PDE_SOLVE_1D messages also identify an explicit failure class, available argument/domain context or solver limit, and a recovery action. The Errors panel and cell inspector show those parts separately while preserving the existing error code and cell address. For example:

CURVE_FIT [iteration_limit_exceeded] (max_iter=1): The iteration budget was exhausted before a convergence criterion was met. Recovery: Review the initial guess, scaling, and tolerance; increase max_iter if the additional work is appropriate.

An initial evaluation failure means the model did not produce finite numeric values; it does not establish a particular mathematical cause. Known iteration or step exhaustion is distinguished from unspecified nonconvergence. PDE step underflow reports its stopping time without diagnosing a singularity. Fits with more than 64 coefficients now return CALC when their iteration budget is exhausted, rather than returning unconverged coefficients. Converged results retain their coefficient-only shape.

No known errors describes loaded results or the runtime's reported snapshot, as stated in the panel. It does not certify unresolved outputs. Saving or updating source is separate from successful calculation; observed calculation errors are reported separately without evaluating the whole model for a status badge.

Leading minus and powers

GRID_NEGATIVE_POWER_GROUPING is a nonfatal authoring warning with a line and column. Grid's existing precedence is unchanged: -2^2 means (-2)^2, giving 4. Write -(2^2) for -4. Both explicit forms are warning-free. The same rule applies to ** and named expressions: -(rate * time)^n still negates the base before raising it to a power. Write -((rate * time)^n) to negate the whole power, or give the positive exposure its own name and then negate that name. Grid does not choose an intention or rewrite source automatically.

Physical scale conflicts

GRID_UNIT_SCALE_MISMATCH identifies known representations that arithmetic does not normalize, such as kilometers and meters in 1km + 500m. Convert one operand explicitly before combining them. This warning preserves legacy numeric semantics; a physical tag is not a conversion. The independent unit_scales strict directive refuses reported conflicts and relevant unverified uses. Explicit unit_scales warn also reports GRID_UNIT_SCALE_UNVERIFIED for unsupported or dynamic contracts. Without a directive, only proven conflicts warn. off retains legacy inference. Unknown coverage is not proof of unit safety. See scale checking.

Scalar root recovery

Known native ROOT, FINDROOT, and GOALSEEK failures preserve their reason, available endpoint evidence, and recovery in Errors, Inspector, and I/O. NO_BRACKET asks the author to review the interval and branch; it does not claim the equation has no solution elsewhere. ARGUMENTS identifies invalid controls, EVALUATION a failed function evaluation, and ITERATION_LIMIT or BUDGET_EXHAUSTED exhausted work. Legacy or unknown messages remain visible without guessing a category. Use Find shared sources in Errors to inspect bounded upstream evidence; unavailable origins stay unknown.

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.

The subsections below explain the diagnostic families worth understanding in depth. The complete generated catalog of every GRID_* diagnostic code lives in diagnostics.md.

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

Address identity: GRID_ADDRESS_UNREPRESENTABLE

Grid rejects explicit A1/R1C1 source addresses outside columns A–XFC (1–16,383) and rows 1–67,108,863 before calculation. These are the coordinates whose identity the current address format can retain; views or imports may have lower limits. XFD is currently outside this range.

A descriptive name such as ContigN50 can match address syntax. Use Contig_N50 instead. The diagnostic includes the source location and naming hint. It does not rewrite existing archives or recover a value previously overwritten by a conflicting address. Review retained source when repairing an affected model.