Concept

Error Handling

Definition

Error handling is the set of patterns a programming language and its libraries use to detect failure, propagate it to the code that can respond, and either recover or fail cleanly. Every nontrivial operation can fail — disks fill up, networks time out, parsers reject input, callers pass nonsense — and how a language expresses that failure shapes the texture of code written in it.

The major patterns are: integer return codes (the C and Unix tradition), exceptions (Java, Python, C#, Ruby), result types or monads (Rust's Result, Haskell's Either, Go's multi-return), and panics or unrecoverable aborts for situations the program cannot meaningfully continue past. Each pattern makes a different trade-off between syntactic noise, type-system support, performance, and how easy it is to forget to handle a case.

Why it matters

How it works

The C-style return code makes failure part of the function's normal return value: zero for success, nonzero for failure, with the specific error available through errno or a similar side channel. The pattern is simple and adds no runtime overhead, but it depends on the caller checking the return value every time. Unix utilities follow the same convention with exit statuses — 0 means success and is the basis of shell && and || short-circuiting.

Exceptions invert the burden: errors propagate up the call stack automatically until something catches them, so the immediate caller does not need to write boilerplate to forward errors. The cost is that exceptions are an alternate control-flow path that is easy to forget about, and a function's failure modes are not visible in its signature unless the language enforces it (Java's checked exceptions try; few other languages do).

Result types put errors back in the signature without giving up automatic propagation. A function returning Result<T, E> forces the caller to acknowledge both branches; Rust's ? operator provides exception-like ergonomics for forwarding errors while still requiring the type to be checked. Panics — Rust's panic!, Go's panic, Python's assert — are reserved for situations the program cannot recover from: state corruption, invariants violated, bugs that should crash loudly rather than continue producing garbage. A well-designed system uses each pattern where it fits and resists the temptation to swallow errors silently anywhere.

Where it goes next

Continue exploring

Tags