Skip to content

Error Model

Spreadsheet errors are first-class values. A formula returning #DIV/0! did not crash — it produced an error value, and the host API call that retrieved it succeeded. This separation is preserved across every binding.

Glossary: cell error vs host failure

A cell error is a value with kind = Error. It travels through the binding as data. A host failure means the host operation itself failed (bad bytes, missing handle, IO error, internal engine failure) and is reported through a separate channel — Status envelope, exception, non-zero exit, or fm_status_t.

ErrorMeaning
#DIV/0!Division by zero
#VALUE!Wrong type or incompatible value
#REF!Invalid reference (deleted sheet, broken range)
#NAME?Unknown name or function
#NUM!Numeric overflow or invalid numeric domain
#N/AValue not available
#NULL!Range intersection produced empty range
#SPILL!Dynamic-array spill conflict
#CALC!Engine could not produce a result
#GETTING_DATAAsynchronous external lookup in progress

Bindings should preserve these values instead of converting them into host exceptions unless the host API is reporting an API misuse or IO failure.

Host failure paths

SurfaceHost failure path
WASMstatus.ok === false or invalid workbook handle plus lastErrorMessage()
PythonFormulonError
CLInon-zero exit code and diagnostic on stderr
C ABInon-zero fm_status_t plus fm_last_error_message() / fm_last_error_context()
MCPMCP error response with structured payload
Native Nodestatus.ok === false on the returned envelope

C ABI value kinds

KindMeaning
FM_VAL_BLANKBlank cell
FM_VAL_NUMBERIEEE-754 double
FM_VAL_BOOLBoolean
FM_VAL_TEXTUTF-8 workbook-owned text view
FM_VAL_ERRORExcel error code ordinal
FM_VAL_ARRAYReserved payload
FM_VAL_REFReserved payload
FM_VAL_LAMBDAReserved payload

Handling pattern

ts
const value = wb.getValue(0, 0, 0)
if (value.kind === ValueKind.Error) {
  // cell error — surface to the user, do not throw
  showInline(value.errorText)
} else if (value.kind === ValueKind.Number) {
  consume(value.number)
}
python
v = wb.get_value(0, 0, 0)
if v.kind is ValueKind.ERROR:
    show_inline(v.error_text)
elif v.kind is ValueKind.NUMBER:
    consume(v.number)