Skip to content

13 · Error Handling

Sigil handles recoverable errors through the effect system rather than exceptions or panic. Declare a Fail effect, perform it when something goes wrong, and install a handle/with block at the call site to decide what happens. The error path is visible in the function’s type — callers cannot accidentally ignore a function that may fail.

error_handling.cssl
// A typed failure effect. E is the error payload.
effect Fail<E> {
fn raise(err: E) -> ! // ! = never returns normally
}
// Parse a positive integer — fails with a message on bad input.
fn parse_positive(s: str) -> i32 !Fail<str> {
match s.parse::<i32>() {
Ok(n) if n > 0 => n,
Ok(_) => perform Fail::raise("must be positive"),
Err(_) => perform Fail::raise("not a valid integer"),
}
}
// Divide — fails on zero denominator.
fn safe_div(a: i32, b: i32) -> i32 !Fail<str> {
if b == 0 { perform Fail::raise("division by zero") }
else { a / b }
}
fn main() !io {
// Handle parse_positive — recover with a default.
let n = handle parse_positive("42") with {
Fail::raise(msg) => {
println!("Parse error: {}", msg);
resume(0) // resume with a fallback value
}
};
println!("parsed: {}", n); // 42
// Demonstrate failure path.
let m = handle parse_positive("-5") with {
Fail::raise(msg) => {
println!("Parse error: {}", msg);
resume(0)
}
};
println!("parsed: {}", m); // 0 (fallback)
// Chained failure — safe_div inside a handler.
let result = handle safe_div(10, 0) with {
Fail::raise(msg) => {
println!("Math error: {}", msg);
resume(-1)
}
};
println!("result: {}", result); // -1
}
parsed: 42
Parse error: must be positive
parsed: 0
Math error: division by zero
result: -1

!Fail<str> in the function signature is a static promise: this function may fail with a str error. A caller that doesn’t install a handle/with block must propagate !Fail<str> in its own signature. There is no way to call parse_positive and silently drop the failure path — the compiler will reject it. Unlike exceptions, Fail effects are tracked per-type, so !Fail<ParseError> and !Fail<IoError> are distinct effects that can be handled independently.


Next → 14 · Modules