Error Handling
Even with compile-time validation, runtime things fail — networks time out,
tools crash, a list index is out of bounds. Scriptum has three layers of
defense: a step-level on error clause, a thread-level on thread error
catch-all, and a default pause-and-resume that never silently drops a failure.
Step-level: on error
Attach one on error: clause to a do step. Pick one of three strategies:
-- Retry up to N times with exponential backoff
do "Call external API" with external_api
url = endpoint
on error: retry 3
-> data
-- On failure, run a different tool instead
do "Fetch data" with http_request
url = api_url
on error: fallback file_read { path = cache_path }
-> data
-- Swallow the error; the binding receives null
do "Call optional API" with http_request
url = api_url
on error: ignore
-> maybe_data| Strategy | Syntax | Behavior |
|---|---|---|
| retry | on error: retry N | retry up to N times with backoff (default 3) |
| fallback | on error: fallback tool { key = val } | run a different tool with these inputs |
| ignore | on error: ignore | swallow the error; binding becomes null |
| (none) | (no clause) | the thread pauses (default — see below) |
Thread-level: on thread error
A script-level catch-all for unhandled errors. Inside it, the error object
(.message, .code, .step, .tool, …) and the thread object (.id,
.status) are available.
on thread error
do "Report failure" with notify
channel = "alerts"
message = "Thread {thread.id} failed at '{error.step}': {error.message}"
emit
status = "failed"
error = error.messageDefault behavior: pause and resume
If a step fails and there is no on error clause, and no on thread error
handler catches it, the thread does not crash — it pauses. Its full
state is persisted, so you can inspect what happened, fix the input or the
script, and resume from the failed step.
RUNTIME ERROR at step "Process result":
Field access failed: 'nonexistent_field' does not exist on object.
Object keys: ["title", "url", "snippet"]
Thread paused. Resume after inspecting / overriding the step input.The priority is: step-level on error first, then on thread error, then the
default pause. A thread never silently swallows a failure — it always either
handles it, runs the global handler, or pauses for a human.
Safe-access operators help you avoid runtime field errors entirely: ? returns
null for a missing field, and ?? supplies a default (see
Expressions & References).
Next: escaping to Python for the odd transformation in Inline Python.