Error Handling
Error Type
Section titled “Error Type”The Error type represents an error condition. An Error has two fields:
| Field | Type | Meaning |
|---|---|---|
code |
ErrorCode |
classification of the error (see ErrorCode) |
msg |
string |
human-facing message (.message is an accepted alias) |
Errors are created with error(code ErrorCode, message string = ""):
do main() { mut a Error = error(.NotFound, "no such file") // code and message mut b Error = error(.NotFound) // message defaults to "" mut c Error = error(.Unknown, "something went wrong") // no more specific code applies println(a) println(b) println(c)}.Unknown (ErrorCode slot 0) is not a “no error” sentinel — “no error” is nil, one level up in the (T, Error) tuple. Reading err.code at all means you are holding a real error.
An Error is usable as a local, a parameter, a return value, and a struct field. It cannot be an array element or a map key/value; to keep a collection of errors, wrap the Error in a struct, or store err.code / err.msg.
Error Returns
Section titled “Error Returns”Functions that may fail return a (T, Error) tuple; these are fallible functions. Destructuring is required; single-var assignment from a fallible function is a compile error. See Return Value Handling for the full rules.
import @io
do read_file(path string) -> (string, Error) { if !io.file_exists(path) { return "", error(.NotFound, "file not found") } return "contents", nil}
do main() { mut contents, err = read_file("data.txt") if err != nil { println(err) } otherwise { println(contents) }}Every standard library function that returns an Error sets both a specific ErrorCode and a fixed message. Only user error() calls may omit the message.
Error Checking
Section titled “Error Checking”Whether an error occurred is checked by comparing to nil:
import @io
do main() { mut content, err = io.read_file("data.txt") if err != nil { println("Error: ${err}") // interpolates err.msg exit(1) } println(content)}Which error occurred is checked on err.code, either with == / != or with when:
import @io
do main() { mut content, err = io.read_file("data.txt") if err != nil { if err.code == .NotFound { content = "" }
when err.code { is .NotFound { println("using defaults") } is .PermissionDenied { println("escalate") } default { println(err.msg) } } } println(content)}err.code is an ErrorCode, an open enum (10.5). A when on it always requires a default branch and can never be #strict.
ErrorCode
Section titled “ErrorCode”ErrorCode is a single, program-wide enum whose variant set is open: it is assembled at compile time from a compiler-owned builtin list plus every user enum marked #error_code. The compiler owns the numbering, so cast(someErrorCode, i64) is that variant’s global slot, not a 0-based position within one enum.
Builtin variants:
Unknown (slot 0), NotFound, AlreadyExists, PermissionDenied, InvalidInput, OutOfRange, Unsupported, Timeout, Interrupted, Closed, WouldBlock, Unavailable, IoFailure, ParseFailure, EncodingFailure, ConversionFailure, NotAuthenticated, ConnectionRefused, ConnectionReset, AddressInUse, BrokenPipe, WriteZero.
#error_code
Section titled “#error_code”The #error_code attribute marks a normal named enum as contributing its variants to the ErrorCode set:
#error_codeconst PaymentErrors enum { PAYMENT_DECLINED PAYMENT_CANCELED PAYMENT_EXPIRED}
do main() {
}error(.PAYMENT_DECLINED, ...),when err.code { is .PAYMENT_DECLINED ... }, andPaymentErrors.PAYMENT_DECLINEDall denote the same value.- The enum must be plain integer-backed. String-backed enums, enums with explicit
= Nvariant values, tagged (payload) enums, and#flagsenums are rejected under#error_code. - Every variant name across the whole
ErrorCodeset must be unique; a name already present (builtin or another#error_codeenum) is a compile error. PaymentErrorsstays usable as its own enum type. A#error_codeenum value and anErrorCodevalue are freely interchangeable in comparisons and assignments — they share one value space.
Runtime Errors
Section titled “Runtime Errors”Certain operations produce runtime errors that terminate program execution:
- Division by zero (integer or float)
- Array index out of bounds
- Map key not found
- Invalid type conversion
Runtime errors include location information (file, line, column).