Error handling

The Result type

Result[T, E] is Cleat's primary error handling mechanism. There are no exceptions.

cleat
let ok: Result[int, string] = Ok(42)
let err: Result[int, string] = Err("not found")

Functions that can fail return Result:

cleat
fn parse_config(path: string) -> Result[Config, string] needs { fs } {
    let text = fs.read(path)?
    let config: Config = json.decode(text)?
    return Ok(config)
}

The ? operator

? unwraps an Ok value. If the Result is Err, it returns immediately from the enclosing function with that error.

cleat
fn load_and_process() -> Result[int, string] needs { fs } {
    let text = fs.read("data.txt")?    // if Err, return Err immediately
    let lines = fs.read_lines("data.txt")?  // same — early return on error
    return Ok(lines.len())
}

The enclosing function must return Result to use ?. The error type must be compatible.

Combining with pattern matching

For finer control, use match:

cleat
let data = match load_config() {
    Ok(config) => config.data,
    Err(e) => {
        log.warn("config failed: ${e}, using defaults")
        default_data()
    },
}

Error propagation chains

Errors bubble up naturally through ?:

cleat
fn fetch_and_decode(url: string) -> Result[Response, string] needs { net } {
    let resp: http.Response = http.get(url)?        // network error → Err
    let data: Response = json.decode(resp.body)?     // parse error → Err
    return Ok(data)
}

fn process(url: string) -> Result[int, string] needs { net } {
    let response = fetch_and_decode(url)?  // propagates either error
    return Ok(response.count)
}

let _ = expr?

Discard the success value while still propagating errors:

cleat
fn setup() -> Result[int, string] needs { fs } {
    let _ = fs.write("config.json", default_config)?  // propagate write errors
    return Ok(0)
}
Edit this page on GitHub