← Back to list

50,000 Go Projects Depended on His Error Fix. Then Go Copied It and Broke His Package.

One engineer's side project became Go's de facto error-handling standard, until the language copied it without fully honoring it.

Wesley Wei in Programmer’s Career · 2026-07-15 18:51 · 50 claps · 4.4 min read paywalled
#coding #programming #technology #golang #productivity
Open on Medium ↗
Wiki topics: 💻 · Programming ⏱️ · Productivity

50,000 Go Projects Depended on His Error Fix. Then Go Copied It and Broke His Package.

One engineer’s side project became Go’s de facto error-handling standard, until the language copied it without fully honoring it.

Photo by Jakub Żerdzicki on Unsplash.

Photo by Jakub Żerdzicki on Unsplash.

Fifty thousand public Go projects. Not fifty thousand downloads.

Fifty thousand separate codebases that added this one library as a direct dependency, plus an uncounted number of private ones behind company firewalls.

Four years later, the language absorbed the exact idea this library was built on. And the official version wasn’t even compatible with the original.

Go shipped without a piece almost every other language had

When Go’s standard library added error handling, it gave you almost nothing to work with beyond a bare error interface. That interface was just a value with a message, no memory of where it came from, no way to attach context as it traveled up through a call stack.

Other languages had exceptions that carried a full stack trace automatically.

Go developers writing anything nontrivial hit the same wall almost immediately: an error surfaces three function calls deep, and by the time it reaches a log line, all you have is a string. You don’t know which file failed to open, or why the caller thought it should have worked.

In 2015, one Go developer got tired of solving that problem by hand and published a small library to solve it once.

The developer was Dave Cheney

Photo by Bjørn Erik Pedersen, via Wikimedia Commons, CC BY-SA 4.0.

Photo by Bjørn Erik Pedersen, via Wikimedia Commons, CC BY-SA 4.0.

Dave Cheney was, and still is, one of the more visible voices in the Go community: a conference speaker, the author of Practical Go, a blogger. His posts on idiomatic error handling and interface design get cited in Go style guides years after he wrote them.

pkg/errors was a side project in that same vein, not a Google-sanctioned initiative.

It gave Go two functions people actually needed. errors.Wrap attached a message and a stack trace to an existing error as it passed upward. errors.Cause let you unwrap that chain back to the original failure when you needed to inspect it.

Cheney presented it at GoCon in Tokyo in 2016. That same June, in a blog post walking through the package’s design, he declared its core API settled: “The errors package, from the point of view of the four package level functions, New, Errorf, Wrap, and Wrapf, is done. Their API signatures are well tested… are unlikely to change at this point.” It didn’t need much more marketing than that.

Within a few years, pkg/errors was — by a wide margin — the closest thing Go had to an unofficial standard library extension. Fifty thousand-plus public repositories imported it directly.

It became such a common assumption in Go codebases that plenty of engineers learned the errors.Wrap pattern before they learned there was any other way to handle errors in the language at all.

The Go team noticed, and built its own version

Illustration by Renee French, via Wikimedia Commons, CC BY 3.0.

Illustration by Renee French, via Wikimedia Commons, CC BY 3.0.

In 2017, the Go team formed a task force to formalize error wrapping into the language itself: Jonathan Amsterdam, Russ Cox, Marcel van Lohuizen, and Damien Neil. They worked from the pattern pkg/errors had already proven at scale across the ecosystem.

Their prototype, xerrors, became the basis for what shipped in Go 1.13 in 2019. fmt.Errorf gained a %w verb for wrapping, and the standard library added errors.Is and errors.As for inspecting the resulting chain.

The idea had won completely. The implementation still lost something in translation.

Cheney’s errors.Cause used a method called Cause() to unwrap back to the original error. Go 1.13's standard library used a method called Unwrap() instead: a different name for close to the same job.

A Go core team member later flagged this directly on the issue tracker as a real defect, not a cosmetic mismatch.

Any program that upgraded to Go 1.13 while depending on a library still using pkg/errors's Cause() internally ran into the same wall. The new standard-library tools couldn't see through those older wrapped errors at all.

Two error-wrapping conventions, doing almost the same thing, unable to read each other’s chains.

pkg/errors's own README eventually added the plainest possible acknowledgment of where that left it: "With the upcoming Go2 error proposals this package is moving into maintenance mode."

No new functionality would be accepted. Bug fixes and pull requests, still welcome.

The project that had quietly become Go’s unofficial standard was now explicitly done growing, four years after Cheney first shipped it, displaced by an official version of his own idea.

I looked for Cheney’s own public reaction to this — a blog post, a talk, anything in his own words about watching the language adopt his pattern without fully preserving compatibility with it. I couldn’t find one.

That absence is worth sitting with rather than filling in: some reckonings don’t get a public statement at all, and the record is allowed to just not say.

Being right and being the answer are not the same achievement

pkg/errors isn't a cautionary tale about a bad idea — it's the opposite.

The Go team’s own task force treated it as proven enough to build the standard library’s version on top of the pattern it had already validated at fifty-thousand-project scale. That’s about as complete a vindication as an open-source maintainer gets.

And it’s still the story of a library quietly filed under maintenance mode, kept alive mostly by codebases too large to migrate off it. Newer projects reach for the standard library version by default and never learn Cheney’s name was ever attached to any of it.

The ecosystem can decide you were right and stop needing you in the same motion.

There’s no contradiction in that — the whole point of a good idea spreading is that it eventually stops requiring its original author.

What’s easy to miss is that “stops requiring the author” and “credits the author” are two different outcomes, and open source only guarantees you the first one.

References


메타데이터
post_id
3f9f9b0cf586
slug
50-000-go-projects-depended-on-his-error-fix-then-go-copied-it-and-broke-his-package-3f9f9b0cf586
url
https://medium.com/programmers-career/50-000-go-projects-depended-on-his-error-fix-then-go-copied-it-and-broke-his-package-3f9f9b0cf586
canonical_url
https://medium.com/programmers-career/50-000-go-projects-depended-on-his-error-fix-then-go-copied-it-and-broke-his-package-3f9f9b0cf586
author_url
https://medium.com/@wesley-wei
status
ok
fetched_at
2026-07-16 16:44:33