Error Handling Without Fear

How to represent, propagate, and respond to errors without panic. Errors are ordinary data and ordinary branches. Treat them that way and the code gets simpler.

Defensive try/catch everywhere is a symptom of not trusting the shape of your own code. An error is not a mystery. It is a value your code produced, at a place you can point to, for a reason you can name.

The goal is not to catch everything as close as possible. The goal is to model expected failures clearly and let each error travel to the layer that can decide what to do.

Errors Are Data #

Errors as Values vs. Exceptions #

Modeling Errors #

A checkout service might return domain outcomes such as CartInvalid, CheckoutUnavailable, PaymentDeclined, PaymentPending, or FulfillmentDelayed. Those are more useful than a generic Error because each one points to a different response.

Propagation #

Boundaries #

Recovering vs. Failing Fast #

Confidence comes from knowing which kind of failure you are handling. A failed schema validation should not enter the retry path. A temporary 503 from a dependency should not be treated like a bug in your domain model.

Security on the Error Path #

The error path is often the least-reviewed path, which makes it a security and privacy surface.

Front End vs. Back End Notes #


Related chapters: Boundaries & Transactions · Do or Do Not. Then Retry. · Writing Insanely Great Error Messages