Zornux docs
Get started Spec

Language

Error Handling

When a runtime error would otherwise stop your program, a try block lets you recover and keep going. Control moves to a catch block, where you can log the problem, retry, or fall back to a safe value — and an optional finally block always runs.

try / catch

Put the risky work inside try. If it fails, the catch block runs instead — the program never crashes:

zornux
try
    show 10 / 0
catch
    show "Couldn't do the math — using a fallback."
end

Inspecting the error

Write catch error to bind the caught error to a value you can read. It carries eight read-only fields — code, name, message, line, column, source, cause, and stack:

zornux
try
    create items = [1, 2, 3]
    show item_at(items, 99)
catch error
    show "Problem " + error.code + ": " + error.message
    show "  at line " + text(error.line) + ", column " + text(error.column)
end
FieldWhat it holds
error.codeThe diagnostic code, e.g. ZX1004.
error.nameThe error's kind, matched by a filtered catch (e.g. DivideByZero).
error.messageThe plain-English explanation.
error.line / error.columnWhere the failure happened (1-based).
error.sourceThe file the failure came from.
error.causeThe underlying error, when this one wraps another (else nothing).
error.stackThe call stack at the point of failure.
error is not a keyword

The name error is only special right after catch — elsewhere it's an ordinary identifier you can use freely.

Filtering by kind, and finally

A try can list several catch clauses. A filtered clause names a specific error kind with catch Kind as error; clauses are tested top to bottom, first match wins, and a bare catch error at the end is the catch-all. A finally block runs on every exit — success or failure. Raise your own error with throw:

zornux
try
    show 1 / 0
catch DivideByZero as error
    show "divide: " + error.message
catch IndexOutOfRange as error
    show "index: " + error.message
catch error
    show "other recoverable error: " + error.code
finally
    show "always runs"
end

Supplying a fallback value

A common pattern is to compute into a variable, falling back when the computation fails:

zornux
create ratio = 0
try
    ratio = 100 / 0
catch
    ratio = 1
end
show "Ratio: " + text(ratio)

What can and can't be recovered

try catches ordinary runtime failures — division by zero, an out-of-range index, a failed conversion, a database error, and the like. Two kinds of failure are deliberately uncatchable and propagate straight past every try:

  • Security violations (ZX1200ZX1299) — you can't swallow an authorization or trust-boundary error.
  • The runaway-loop guard (ZX0713) — a loop that exceeds its limit is stopped for good.
Recovery is for expected failures

Use try where a failure is a normal outcome you can handle — not to mask a security check or an infinite loop. Those are bugs the language refuses to let you hide.

Related: transactions roll back

The data layer builds on the same idea. A transaction on DB … catch error … end commits when its body finishes cleanly and rolls the whole batch back when a recoverable error occurs — try's all-or-nothing sibling for persistence.

Next: doing several things at once — Concurrency.