Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Error Codes

Every diagnostic Suji prints carries a numeric code. This page lists all of them.

How Errors Behave

Suji has no error-handling construct: no try/catch, no throw, no Result or Option type, no defer. Any diagnosed error terminates the script immediately with exit status 1, and there is no way to trap it from Suji code. The only strategy is to check before you act — see Error Handling Deep Dive.

Two failures escape this taxonomy because they abort the process before a diagnostic can be produced. Neither carries a code, and neither can be caught:

FailureWhat you seeExit status
Numeric overflow, including 10 ^ 16thread 'main' panicked … Multiplication overflowed101
Recursion deeper than a few hundred framesthread 'main' has overflowed its stack134

Code Ranges

RangePhaseMeaning
1xxLexingThe source could not be turned into tokens
2xxParsingThe tokens do not form a valid program
4xxRuntimeThe program started and then failed while running

A 1xx or 2xx error means nothing ran at all. A 4xx error means everything before the failing line already executed, including its side effects.

Diagnostic Format

The interpreter prints a framed diagnostic to stderr, followed by a one-line summary. The code appears in brackets before the title:

[403] Error: Index out of bounds
   ╭─[ e1.si:4:9 ]
   │
 4 │ println(xs[5])
   │         ──┬──
   │           ╰──── Index 5 out of bounds for length 2
   │
   │ Note 1: Use list::length() to check the size before indexing
   │
   │ Note 2: Check array/map bounds and key existence
   │
   │ Note 3: Use length() methods to verify bounds before access
───╯
Error: Index out of bounds: Index 5 out of bounds for length 2

Reading it: 403 is the code, Index out of bounds is the title, e1.si:4:9 is the file, line and column, the underline marks the offending expression, and the notes are generic suggestions for that error category.

Lexer Errors (1xx)

CodeTitleUsual cause and fix
101Unterminated string literalA quote was never closed. Check for a stray " or ', and remember that """ must be closed by """
102Unterminated shell commandA backtick template was never closed. Escape literal backticks inside strings as \`
103Unterminated regex literalA /pattern/ is missing its closing slash. Escape a literal slash inside the pattern as \/
104Invalid escape sequenceOnly \n \t \r \" \' \ \ $exist.\u0041, \0and\e` are not supported; write the character directly
105Invalid number literalNumbers are decimal digits with at most one .. Hex, octal, binary, digit separators and exponents do not exist
106Unexpected characterA character that is not part of any token, often a smart quote pasted from a document, or @/?

Parser Errors (2xx)

CodeTitleUsual cause and fix
201Unexpected tokenSomething is in a position the grammar does not allow. The classic case is a missing comma after a bare-expression match arm
202Unexpected end of inputA brace, bracket or parenthesis was never closed
203Parse errorA general parse failure that does not fit a more specific code
204Multiple export statements foundA file may contain at most one export. Merge the values into a single map
205Expected tokenA specific token was required and something else appeared, for example a missing => in a match arm
206Expected item name after :An import path ends in a colon, as in import std:
207Expected alias name after asimport std:println as has no name after as. Note that aliasing a single-segment local import is also rejected

Runtime Errors (4xx)

Types and Operations

CodeTitleUsual cause and fix
400Type errorMixed types in an operation. "a" + 1, nil || "x", indexing a tuple, comparing a number with a string using <
402Invalid operationThe operation is not defined for these values at all, such as an unsupported unary application
410Invalid number conversion"abc"::to_number() on text that is not numeric. Validate with a regex before converting

Names and Access

CodeTitleUsual cause and fix
401Undefined variableA typo, a missing import, or a keyword from another language such as if being read as an identifier
403Index out of boundsA list index outside 0 .. length-1 (or the negative equivalent). Check xs::length() first
404Key not foundm:key or m[k] on an absent key. Use m::get(k, default) or m::contains(k)
405Invalid key typeMap keys must be numbers, booleans, strings or tuples. Lists and maps cannot be keys
412String index errorA character index outside the string. Check s::length() first
413Range errorRange bounds must be integers, and very large ranges allocate a full list

Calls and Control Flow

CodeTitleUsual cause and fix
408Arity mismatchWrong number of arguments. Give the parameter a default value if it should be optional
409Method errorThe method does not exist for that type. Check the spelling and the type’s method list
411Internal control flow errorA break, continue or return escaped its construct. Usually indicates a bug worth reporting
416Conditional match errorAn arm of a match { … } did not evaluate to a boolean
426Map method errorA map method was called with the wrong arguments, for example m::get() with no key

Collections and Destructuring

CodeTitleUsual cause and fix
414List concatenation error+ was used between a list and a non-list. Use xs::push(v) to add one item
415Map contains errorm::contains(k) was called with a key of an unusable type
434Destructuring type errora, b = value where the right side is not a tuple
435Destructuring arity mismatchThe number of targets does not match the tuple size. Use _ to discard a position
436Invalid destructuring targetA destructuring target is not assignable

Pipes

CodeTitleUsual cause and fix
429Pipe stage type errorA | stage is neither a closure call nor a shell template
430Empty pipe expressionA | has nothing on one side
431Pipe execution errorA stage of a | pipeline failed while running
432Pipe apply type error|> has a non-function on the right
433Pipe apply type error<| has a non-function on the left

System, Streams and Regex

CodeTitleUsual cause and fix
406Shell command failedA backtick command exited non-zero. Neutralise it with `cmd || true` or make the command print a value you can match on
407Regex errorThe pattern could not be compiled, or ~ was applied to something other than string ~ regex
427Stream errorA read or write on a closed, missing or unreadable stream

Data Formats

CodeTitleUsual cause and fix
417JSON parse errorMalformed JSON text
418JSON generation errorThe value contains something JSON cannot hold, such as a function or a regex
419YAML parse errorMalformed YAML text, usually indentation
420YAML generation errorThe value contains something YAML cannot hold
421TOML parse errorMalformed TOML text
422TOML generation errorTOML has no nil, and functions and regex cannot be written
423TOML conversion errorA TOML key was not a string, or a nil appeared in the value
424CSV parse errorUnclosed quotes or an unusable delimiter
425CSV generation errorcsv:generate expects a list of lists of strings; convert numbers first
428Serialization errorA value that cannot be serialised at all, such as a stream, reached a format writer

Checking Before You Act

Because nothing can be caught, the defensive patterns below are the whole error-handling story.

import std:println

safe_divide = |a, b| {
    match {
        b == 0 => nil,
        _ => a / b,
    }
}

config = {host: "localhost"}
xs = [1, 2, 3]

println(safe_divide(10, 0))            # nil
println(safe_divide(10, 4))            # 2.50
println(config::get("port", 8080))     # 8080
println(config::contains("host"))      # true
println(xs::length() > 0)              # true
println(xs::first(0))                  # 1

For a shell command that may fail, make failure produce a value instead of an error:

import std:println

status = `test -f /definitely/not/here && echo found || echo missing`

println(status)  # missing

See Also