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 runtime-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 |
#CIRC! |
Generated when the dependency graph contains a cycle |
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 #CIRC! 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 | Match the kind to the tag, or remove the tag |
CIRC |
#CIRC! |
A cyclic dependency was detected during model build | Break the cycle |
Three additional internal codes you may see in API responses:
| Code | Source | Meaning |
|---|---|---|
TIMEOUT |
External worker | The worker exceeded its timeoutMs budget |
EXTERNAL |
External adapter | The adapter raised an exception |
STALE_FALLBACK |
Runtime | A fresh value failed; the runtime returned 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.
A1 = #N/A
A2 = A1 + 5 # → #N/A (propagated)
A3 = SUM(A1, 1, 2) # → #N/A (propagated)
A4 = IFERROR(A1, 0) # → 0 (handled)The first error encountered in a positional argument list wins. Named arguments don't change this rule.
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 Errors (Build-Time, Not Runtime)
Some errors fire at build time (when the model is parsed or
constructed), not at evaluation time. They surface as diagnostics in
the API response, not as cell values.
| Diagnostic | Cause |
|---|---|
Parse error at line N |
Source could not be parsed |
Cyclic reference detected |
Same as #CIRC! 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 |
Mixed ownership: B1 has both top-level and rule-action assignments |
A target cannot be owned by both |
A model with build-time diagnostics will not deploy. Fix all diagnostics first.
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 as 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 as 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 cell whose external call is queued or running is not an
error. It carries a previous cached value (or BLANK) with a stale
status. Detect via the API status field, not by ISERROR.
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.