Skip to content
Nicolas Perron
Français
Back to the blog
Architecture

Exceptions or return values: rethinking error handling

Error handling is one of the most misused aspects of programming. Separating the exceptional from the normal changes a lot.

1 min read

Error handling is probably one of the most misused aspects of programming. There are generally two approaches: throwing exceptions, or returning errors through return values.

A simple but fundamental distinction

In languages that lean heavily on exceptions, experience and readings like Code Complete led me to a simple rule:

  • Exceptions should be reserved for genuinely exceptional situations.
  • Functional errors should be handled through return values.

A validation error — an invalid postal code, say — is not exceptional. It’s a normal scenario in the business domain. Using an exception there breaks the normal flow of the program, and it’s rarely efficient.

Conversely, an unavailable database, a network outage or data corruption: that’s where we’re truly in exceptional territory.

The Go approach

The Go language takes a different stance: no exceptions, every error is a returned value.

res, msg, err := computeAndMessage(a, b)
if err != nil {
    fmt.Println("Error detected:", err)
}

It’s more verbose, yes. But also more explicit and simpler. Above all, it forces you to treat every error as part of the program’s normal flow. Another advantage: the ability to return multiple values, which makes handling the error alongside the result feel natural.

It’s not a universal solution, but an approach worth considering — especially in architecture.