Error Handling
Calls that can fail have a fallible type T!. You either propagate the failure with try or handle it with else.
try and else
try e propagates a failure as an error response; let x = e else err { … } runs a (diverging) block that can inspect the error:
route GET "/proxy/:id" (id: int) -> User {
respond try backend.getUser(id) # try -> auto 502 on failure
}
route GET "/safe/:id" (id: int) -> User {
let u = backend.getUser(id) else e { # else -> handle it
status 502
respond "upstream down: {e.message}\n"
}
respond u
}The built-in Error { status: int, message: string } is what a bare else binds.
Unwrapping optionals
The same else form unwraps an optional or runs a diverging block:
let header = request_header("Authorization") else { fail 401 "missing authorization" }Typed errors
A function can declare an error type with -> T ! E (where E is a sum type). It fails with a variant, and the fallible T! carries that typed value so a caller can match on it. A bare T! still uses the built-in Error.
type LookupError =
| NotFound
| Invalid(string)
fn lookup(id: int) -> string ! LookupError {
if id < 0 { fail LookupError.Invalid("id must be non-negative") }
if id > 100 { fail LookupError.NotFound }
return "user-{id}"
}
route GET "/user/:id" (id: int) -> string {
let name = lookup(id) else e { # handle each variant
let code = match e { NotFound => 404, Invalid(_) => 400 }
let msg = match e { NotFound => "no such user", Invalid(reason) => "bad: {reason}" }
status code
respond msg
}
respond "found {name}"
}
# Without `else`, an unhandled typed error becomes a 500 with the error as JSON.
route GET "/raw/:id" (id: int) -> string {
respond try lookup(id)
}try in a fallible fn propagates the error across a call chain, handled once at the boundary with else / match.
fail
fail STATUS "message" short-circuits with an error response (used in routes, decorators, hubs, and transactions). The status is any int expression — a literal, a variable, or a std.HttpStatus value (fail std.HttpStatus.NotFound "no such user") — and the message any string expression. In a typed-error function, fail Variant(…) raises the typed value instead.