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.

A host failure (bad bytes, missing handle, IO error) means fix the integration; a cell error means show it inline and keep going.

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
#FIELD!Invalid rich-data-type field reference
#BLOCKED!Action blocked by workbook or data-type policy
#CONNECT!External data connection failure
#EXTERNAL!External function or dependency error
#BUSY!Operation currently busy (e.g. a real-time-data provider)
#PYTHON!Error raised while evaluating a PY cell
#UNKNOWN!Unrecognized or unmapped error code

This is the full, wired ErrorCode set (src/value.h's kErrorTable); build any host-side lookup table against all 17 codes, not just the classic ten.

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.
  // value.errorCode is a formulon.ErrorCode ordinal; map it to a
  // display string (e.g. "#DIV/0!") with your own lookup table.
  showInline(value.errorCode)
} else if (value.kind === ValueKind.Number) {
  consume(value.number)
}
python
v = wb.get_value(0, 0, 0)
if v.kind is ValueKind.ERROR:
    # v.error_code is an int ErrorCode ordinal; map it yourself.
    show_inline(v.error_code)
elif v.kind is ValueKind.NUMBER:
    consume(v.number)