Error handling
Make failure part of a function’s interface and choose how callers recover.
On this page
An error-returning call needs an explicit handling decision. The caller can recover, stop its current work, or pass the error to its own caller.
Declare a failure#
A named error type gives a function a small set of failure codes:
error QuantityError (not_positive)
fn checked_quantity(value: int) int !QuantityError {
if value <= 0 : throw .not_positive
return value
}
fn main() {
let quantity = checked_quantity(-2) !? 1
println(quantity) // 1
}
!QuantityError declares that the function may throw that error. throw .not_positive exits through its error result. The caller uses !? 1 to recover with a replacement quantity.
Handle the problem where you have context#
An error block can explain the failure and leave the current operation. This example does not continue with invalid input:
fn main() {
let quantity = "many".to(int) ! {
println("Enter a whole number, such as 3.")
return
}
println("Quantity: %quantity")
}
When a call's value is used, its error branch must supply a replacement or leave the flow with return, throw, break, continue, or a non-returning call such as panic.
Pass an error to your caller#
Use !> when the current function cannot usefully recover:
fn doubled_input(text: String) int !SyntaxError {
let value = text.to(int) !>
return value * 2
}
fn main() {
let result = doubled_input("21") ! {
println("Could not parse the input.")
return
}
println(result) // 42
}
The enclosing function must declare a compatible error type. Passing an error preserves its code and payload.
Attach details to an error#
Payloads carry information a caller needs to make a decision or explain the problem:
error NameError (empty) payload {
message: String
}
fn check_name(name: String) !NameError {
if name.is_empty() {
throw .empty { message: "A name is required." }
}
}
fn main() {
check_name("") ! {
println(E.message)
}
}
Inside a handler, E is the caught error. E.code identifies its code, and payload fields are available by name. Required payload fields must be supplied when an error is thrown; a field with an explicit default may be omitted.
Choose the right operator#
| Form | On failure |
|---|---|
call() !? value |
Use a fallback value |
call() ! { ... } |
Run a handler |
call() !> |
Return the error to the caller |
call() !! |
Panic |
call() _ |
Discard the error and the return value |
Use a panic when failure means the program cannot continue sensibly. Use _ only when ignoring the outcome is intentional. Neither is a substitute for handling expected bad input.
A missing nullable value is a separate case: use ?? for a null fallback, as described in Values & types.