Learning on Web Dev Open is free for all.

Systems Thinking > Failure, deliberatelyErrors are values too
Phase 03Failure, deliberately147 of 434

Errors are values too

throw is a control-flow operator with terrible ergonomics. Sometimes it is right, and knowing when is most of the skill.

Concept13 minAI pair

A user typing an invalid email is not exceptional. A 404 on a resource the user asked for is not exceptional. A disk that has vanished mid-write is. The distinction matters because throw is invisible in a signature, unwinds past every intermediate frame, and gets caught by whoever happens to have a try block, which is frequently the wrong person.

For expected failures, returning them is often clearer: a discriminated union of { ok: true, value } and { ok: false, error } makes the failure part of the type, so the caller cannot forget it and the compiler says so. You do not need a library for this and you should not adopt it everywhere: the cost is ceremony at every call site, and for genuinely exceptional cases that ceremony buys nothing.

The rule that survives contact with real code: throw for things a caller cannot reasonably handle, return for things it must. Then keep the throwing paths narrow enough that a single boundary can catch them all and turn them into something a user can read.

You should now be able to

  • Distinguish an expected failure from a genuine exception
  • Return a failure as a value where that is clearer
Ask the community

Loading…