ADR 0053 — Mixed-text propagation of Excel error sentinels
- Status: accepted
- Date: 2026-05-22
- Spec target: XTL 0.1
- Affects: language.md § "Arithmetic", evaluation.md § "Source Value Model", ADR-0017, ADR-0025
Context
language.md § "Arithmetic" pins the rendering of #DIV/0! in
three positions: numeric single-expression cell (real Excel error
cell), text-format single-expression cell (the string "#DIV/0!"),
and mixed-text / & concatenation (the string "#DIV/0!"
substituted at the position). That paragraph covers division by
zero per ADR-0025.
It does NOT cover the other six Excel error sentinels — #N/A,
#VALUE!, #REF!, #NAME?, #NUM!, #NULL!. These never arise
from a spec-conformant operation as the operation's result
(XLOOKUP no-match raises xl3/xlookup/no-match, etc.), but they
DO appear when:
- A source cell contains the error directly (Excel pre-populated).
- A formula cell's cached result is one of the sentinels.
ADR-0017 says such source values flow as empty per ADR-0007:
they participate in IFEMPTY, COUNT([field]), and the comparison
algorithm as empty. That is well-defined for the read side.
What is missing is the write side: if an author writes
{{ IFEMPTY([cell-that-is-N/A], "missing") }}, the result is
"missing" (good, defined by ADR-0017). But if they write
{{ [cell-that-is-N/A] }} in a numeric-formatted single-expression
cell, what is the rendered output? The empty-on-read rule says it
flows as empty; ADR-0007 says empty stringifies to ""; numFmt
coercion of "" to a number is xl3/cell/numfmt-coercion per
ADR-0026. That is the current impl behavior, but it is not
explicitly stated.
The mixed-text case is even less clear. Order date: {{ [cell-N/A] }}
— is the empty value rendered as "" (so the cell reads
"Order date: "), or as the sentinel string (so the cell reads
"Order date: #N/A")?
ADR-0025 set the precedent for #DIV/0!. This ADR completes the
matrix for the other six.
Considered Options
A. Treat all seven sentinels uniformly via the empty-value rule.
A source-side error reads as empty (ADR-0017). In mixed-text it
contributes "" to the rendered string. In a numeric single-
expression cell it raises xl3/cell/numfmt-coercion. Most
consistent with ADR-0017.
B. Pass through the sentinel string in mixed-text only. A
source #N/A reads as empty for IFEMPTY/COUNT semantics, but when
substituted in a mixed-text cell, the literal sentinel string
appears. Pro: matches Excel display intuition (an error stays
visible). Con: split semantics — the same value behaves one way for
predicates, another for rendering.
C. Carry the sentinel as a tagged error value that propagates
through expressions. A #VALUE! source flows through +, &,
comparisons as an "error" type. This is what Excel does internally.
Pro: most Excel-faithful. Con: large new typing surface; needs an
error-arithmetic table; out of scope for 0.1.