Skip to main content

Error Handling

Every error carries a status code and a message. Scripts run from a file include line numbers in error messages.

Error categories

Lexical

UNEXPECTED_CHARACTER
UNTERMINATED_STRING
UNTERMINATED_COMMENT

Syntax

EXPECTED_TOKEN
UNEXPECTED_TOKEN
UNEXPECTED_EOF
INVALID_STATEMENT
INVALID_FUNCTION_DEF
INVALID_LITERAL
INVALID_ASSIGNMENT_TARGET

Semantic

UNKNOWN_VARIABLE
UNKNOWN_FUNCTION
UNDEFINED_KEY
ARRAY_INDEX_OUT_OF_RANGE
NOT_CALLABLE
REASSIGN_CONSTANT
REASSIGN_RESTRICTED
MODIFY_CONSTANT
MODIFY_RESTRICTED
INVALID_ACCESSOR
INVALID_OPERATOR
INVALID_ITERABLE
INVALID_ASSIGNMENT_TARGET
INVALID_ARGUMENT_COUNT
INVALID_OPERAND_TYPE
INVALID_ARGUMENT
INVALID_CONVERSION
TYPE_ERROR

Runtime

DIVISION_BY_ZERO
MODULO_BY_ZERO
STACK_OVERFLOW
ARITHMETIC_ERROR
OUT_OF_MEMORY
RUNTIME_ERROR
UNSUPPORTED

File

FILE_NOT_FOUND
FILE_UNREADABLE
IMPORT_NOT_FOUND
IMPORT_READ_FAILED
PLUGIN_LOAD_FAILED

Common failure modes

// division by zero
print(1 / 0) // DIVISION_BY_ZERO

// reassigning a constant
const pi = 3.14
pi = 3 // REASSIGN_CONSTANT

// missing variable
print(undefined_name) // UNKNOWN_VARIABLE

// incompatible comparison
print(1 == "one") // TYPE_ERROR

// deep recursion
fn boom() { return boom() }
boom() // STACK_OVERFLOW (limit 256)

Errors from async work

Errors raised on background tasks (spawned fibers, network receive loops, timers) are recorded and surfaced rather than lost:

  • std.async.await(future) re-throws the task's error (as Async error: <message>). Use this for spawn/defer and single-shot timers, whose errors live on the returned future.
  • Background objects with no caller record the most recent failure and expose it via last_error(): repeating-timer handles (handle.last_error()), and the std.net objects tcp_client, tcp_server, udp, websocket, and http_server (null when there is none).

See std.time for details on which surface applies to each kind of background work. Concurrency errors in particular are covered in Concurrency — Errors.

Assertions

std.assert is the lightweight way to fail fast in tests and preconditions:

std.assert.assert(x > 0, "x must be positive") // throws on failure
std.assert.assert_eq(40 + 2, 42) // equality check
std.assert.assert_throws(fn() { 1 / 0 }) // expects an error

A failed assertion throws a normal Scrii error with a message, and in async tasks it is stored on the future and re-thrown by await — see std.assert for the full API.

Embedding

Host callbacks that throw from C++ surface in the script. Prefer throwing ScriptError{status::..., msg} so scripts receive a clean status and message. See Embedding.