DEV Community

Cover image for Go error handling won and the if err != nil crowd deserves the win
Aditya Agarwal
Aditya Agarwal

Posted on

Go error handling won and the if err != nil crowd deserves the win

The competition for the most used code snippet has a clear winner: if err != nil. Whoever wrote this ten thousand times should get the award.

A Medium post was published on August 9, 2026, which was a retrospective comparing a Go vs a Rust production backend rewrite. It re-ignited the oldest flamewar on the internet: is Go's error handling a wart or a feature?

The complaint everyone repeats

You've probably heard that Go is too wordy, if err != nil is just clutter, proper languages use Result and ?.

The complaint is further substantiated by the Go Developer Survey from April 9, 2024. 13% of the respondents indicated that "verbosity of error handling" was a challenge.

However, if you take another look at the survey, you'll see that Go has a satisfaction rate of 93%. 🤔

So 13% grumble about the typing while nine out of ten devs are happy. This is not a language "falling apart"; it is a tradeoff that people made on purpose and keep making.

The try() near-miss

Here's the part that slips people's minds. Go almost gave up.

One of the Go co-designers, Robert Griesemer, submitted Proposal #32437 on June 4, 2019, to include a built-in try(). With this, you would simply write f := try(os.Open(filename)) and all the boilerplate would disappear.

Sounds nice, right? The community disagreed hard.

On July 16, 2019, the proposal was closed and rejected. The feedback was overwhelmingly negative, and the people who work on Go every day took one look at the shortcut and said, "No, thanks."

That is unusual. The majority of languages rush to embrace sugar. The Go language users made a choice to retain the "annoying" thing because the "annoying" thing is effective.

Verbosity is the point

Let's go back to January 12, 2015 when Rob Pike said this in "Errors are values": "Errors are values. Values can be programmed, and since errors are values, errors can be programmed.."

That is the basic philosophy. An error should not be a magical control-flow escape mechanism. It is simply a value that needs to be managed at the point where it occurs.

Hiding an error behind a ? is saying "not my problem, bubble it up". Typing if err != nil makes you stop and decide. Wrap it. Log it. Retry it. Bail.

That verbosity is the point: I want to see every failure, not sweep it under a syntactic rug. The mantra in the Go community is "errors are values" and it's not uncommon to see functions in Go returning an error as their last return value. This makes error handling more visible and helps developers remember to handle it.

→ You read top to bottom, no jumping to find where a ? unwound the stack
→ Every failure path is visible in the diff during review
→ The code you wrote at 3am five years ago still reads the same at 3am today

Old Go code doesn't become unnecessarily complicated over time.

The breadcrumb trail

On September 3, 2019, Go 1.13 was released. It introduced the %w verb for fmt.Errorf, along with the errors.Is and errors.As functions.

This eliminated the excuse of "manual wrapping" and gave you a straight line through your stack.

if err != nil {
return fmt.Errorf("could not fetch user %d: %w", id, err)
}
Enter fullscreen mode Exit fullscreen mode

Uber, Cloudflare, and Monzo use this exact pattern to run their backend microservices. If and when a request dies in production, the wrapped error will read like a breadcrumb trail from the crash back to the cause.

You don't need a decoder ring or to dig through stack traces. You simply get a string that indicates where the error occurred and what the code was trying to do.

What I actually think

I run a small startup. We ship fast and we're on call for our own mistakes.

The most enjoyable aspect of writing explicit errors is not the writing part. It is reading it six months later when I've forgotten absolutely everything and something's on fire.

Code that contains an excessive amount of unnecessary or repeated information is uninteresting and not engaging to read. However, when you're in a high-pressure situation trying to troubleshoot and fix a problem in a production environment, you need that kind of boring code that is clear, simple, and gets the job done efficiently!

Those who used if err != nil didn't really fail. They tolerated the redundancy in order for themselves and others to easily understand the code even when tired. This is not a flaw. It's like having good coding habits integrated into the language.

Here's my question to you: Has a ? operator ever saved you more time debugging than an explicit error trail has cost you? I'm genuinely interested if there are examples.

Top comments (0)