glerror
Error handling utilities with support for error kinds, context, and sources.
Usage
Simple string-based errors
import glerror
pub fn fetch_user(id: Int) -> glerror.Result(User) {
case http.get("/users/" <> int.to_string(id)) {
Ok(response) -> parse_user(response)
Error(_) -> Error(glerror.error("HTTP request failed"))
}
|> glerror.context("fetching user " <> int.to_string(id))
}Custom error kinds
import glerror
pub type DatabaseError {
NotFound
ConnectionFailed
QueryError(details: String)
}
fn format_database_error(kind: DatabaseError) -> glerror.Format {
func(_) {
case kind {
NotFound -> "not found"
ConnectionFailed -> "connection failed"
QueryError(details) -> "query error (" <> details <> ")"
}
}
}
pub fn get_record(id: Int) -> Result(Record, glerror.KindError(DatabaseError)) {
case execute_query("SELECT * FROM records WHERE id = ?", [id]) {
Ok(record) -> Ok(record)
Error(_) -> Error(glerror.new(glerror.Kind(kind: NotFound, format: format_database_error(NotFound))))
}
|> glerror.context("fetching record")
}Displaying errors
let err = glerror.error("connection refused")
|> glerror.add_context("connecting to database")
|> glerror.add_context("initializing application")
// Single-line format
glerror.to_string(err)
// "connection refused [connecting to database, initializing application]"
// Pretty-printed format
glerror.pretty_print(err)
// error: connection refused
// context:
// 0: connecting to database
// 1: initializing applicationErrors with a source
Errors can include a source — another error that caused them. This is useful for wrapping lower-level errors with higher-level context.
let source = glerror.error("HTTP 404")
let err = glerror.error("Not found")
|> glerror.add_context("fetching user")
|> glerror.add_context("loading dashboard")
|> glerror.add_source(source)
glerror.pretty_print(err)
// error: Not found
// context:
// 0: loading dashboard
// 1: fetching user
// sources:
// ╰─▶ HTTP 404Multiple sources
An error can have more than one source:
glerror.to_string(err)
// "Database error (sources: Source A, Source B)"
glerror.pretty_print(err)
// error: Database error
// sources:
// ├─▶ Source A
// ╰─▶ Source BNested sources
Sources can themselves have sources, forming a chain that traces the full error path:
let tcp_err = glerror.error("TCP timeout")
let db_err = glerror.error("Database error")
|> glerror.add_context("connecting to database")
|> glerror.add_source(tcp_err)
let err = glerror.error("Not found")
|> glerror.add_context("fetching user")
|> glerror.add_context("loading dashboard")
|> glerror.add_source(db_err)
glerror.pretty_print(err)
// error: Not found
// context:
// 0: loading dashboard
// 1: fetching user
// sources:
// ╰─▶ error: Database error
// context:
// 0: connecting to database
// sources:
// ╰─▶ TCP timeoutMultiple nested sources are displayed as a tree:
// error: Not found
// context:
// 0: fetching user
// sources:
// ├─▶ error: Database error
// │ context:
// │ 0: connecting to database
// │ sources:
// │ ╰─▶ TCP timeout
// ╰─▶ error: Invalid: config
// context:
// 0: parsing config
// sources:
// ╰─▶ Missing field