Open-source project
pkg/errors avatar
pkg/errors

pkg/errors: wrapping Go errors without losing the original cause

Simple error handling primitives

8,255 stars712 forksGoBSD-2-Clause

At a glance

What is it?
pkg/errors adds context to Go error values while keeping the original error inspectable. It is in maintenance mode, and its roadmap has been frozen since the Go 2 error proposals landed.
Who is it for?
Adopt pkg/errors if your codebase predates Go 1.13 error wrapping and you need stack traces attached to errors at the point of failure. Do not adopt it for new code that can use fmt.Errorf with %w and errors.Is/errors.As, because the project itself is in maintenance mode and is not accepting proposals for new functionality.
Can I use it commercially?
Yes. BSD-2-Clause is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Activity is slowing. The repository last received commits 6 months ago.
What is it written in?
Mainly Go, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on September 29, 2026, and from our analysis. They are not legal advice.

DEEP OPEN-SOURCE ANALYSIS

The problem pkg/errors solves in a Go call stack

The traditional Go idiom is `if err != nil { return err }`. Applied recursively up the call stack, the README states, this produces error reports without context or debugging information. A caller at the top of the stack sees the same error value that was produced deep inside, with no indication of which call path produced it or what operation was being attempted. pkg/errors exists to add context to the failure path without destroying the original error value. It is aimed at Go programmers who maintain code that predates the standard library's error wrapping and who want stack information attached at the point where the failure occurred, rather than reconstructed later.

How wrapping and Cause work together

The core mechanism is a stack of errors. `errors.Wrap` returns a new error that adds context to the original, so a read failure becomes a wrapped error carrying the message "read failed" plus the underlying value. Because Wrap builds a chain, the original error is still reachable. The README defines a `causer` interface with a single method, `Cause() error`, and states that any error value implementing it can be inspected by `errors.Cause`. Cause walks the chain recursively and returns the topmost error that does not implement causer, which is assumed to be the original cause. That design gives you two views of the same failure: the wrapped message for logs and humans, and the unwrapped value for type switches and sentinel comparison. The trade-off is that inspection only works if every layer in the chain implements causer; a layer that returns a plain error without Cause ends the walk, and Cause will hand back that intermediate value rather than the true origin.

Installing pkg/errors and wrapping a first error

The README gives a single install command. Run it from your module directory, and Go fetches the package at the import path shown below.

bash
go get github.com/pkg/errors

Once the module is in your build, the first real use is to wrap an error at the point where it is produced, so the failure path carries context rather than a bare value. The README's example reads from a reader and wraps any failure with the message "read failed".

go
_, err := ioutil.ReadAll(r)
if err != nil {
        return errors.Wrap(err, "read failed")
}

After this, logging `err` shows the context message together with the original error text, and the underlying value is still reachable through Cause.

Wrapping a read failure and inspecting the cause

The README's own example wraps an error from `ioutil.ReadAll` with the message "read failed". The wrapped value carries that context while the original error remains available through Cause. A type switch on `errors.Cause(err)` then lets you handle a known error type specifically and fall through to a default branch for anything else. The README shows exactly this shape: switch on the cause, match `*MyError`, and handle it; otherwise treat the error as unknown. If you log the wrapped error directly, you get the context message; if you need to branch on the concrete type, you go through Cause first.

Maintenance mode, the 1.0 roadmap and what that means for upgrades

The README states plainly that with the upcoming Go 2 error proposals, the package is moving into maintenance mode. The published roadmap is short: 0.9 removes pre Go 1.9 and Go 1.10 support and addresses outstanding pull requests if possible, then 1.0 is the final release. The contributing section says the package is not accepting proposals for new functionality, though pull requests, bug fixes and issue reports are welcome, and that changes should be discussed in an issue first. The release history backs the maintenance framing: v0.8.1 in January 2019, v0.9.0 and v0.9.1 in January 2020, and nothing after that in the release list, even though the repository shows a push in March 2026. So the practical upgrade cost is low but so is the feature velocity: you are adopting a frozen API surface, not a library that will grow with your needs. The licence is BSD-2-Clause, a permissive licence that places few conditions on redistribution; check the LICENSE file for the exact terms rather than relying on the identifier alone.

Where pkg/errors is the wrong tool

If your project already targets a Go version with the standard error wrapping facilities, the repository layout itself hints at friction: there is a go113.go file alongside errors.go, which suggests version-specific handling inside the package. New code that can use the standard library's wrapping and inspection has little reason to add a dependency whose own README declares it in maintenance mode and closed to new functionality. There is also a correctness trap in Cause: it assumes the topmost non-causer error is the original cause, so if an intermediate layer returns an error that does not implement Cause, you get that layer, not the root. Code that depends on reaching a sentinel value through a long chain should verify the chain actually terminates where expected. Finally, the Makefile's check target pulls in staticcheck, misspell, unconvert, ineffassign, unparam and errcheck, which is a heavier toolchain than many small projects want to reproduce for a dependency they do not modify.

The standard library alternative and the real difference

The alternative is Go's own error wrapping, which the README frames as the reason for the maintenance mode. The difference is in the inspection contract. pkg/errors defines its own `causer` interface and a `Cause` function that walks it, and it attaches stack information at wrap time. The standard library approach uses its own wrapping verb and its own matching functions, so error inspection goes through the standard library rather than through a package-level Cause call. For a codebase already written against pkg/errors, migrating means rewriting every inspection site, not just the wrap calls. For a new codebase, choosing the standard library means no third-party error dependency at all. The repository's go113.go suggests the package itself has had to account for the newer Go error behaviour, which is a signal that the two approaches now overlap rather than complement each other.

Who should adopt pkg/errors, and what to verify first

Adopt it if you maintain a Go service written before the standard wrapping facilities existed, you want stack traces attached where errors are created, and you are not planning to migrate the error layer soon. Skip it for greenfield code that can use the standard library, and skip it if you need the library to accept new features, since the README says proposals for new functionality are closed. Before adding it, check three things in your own code: whether any error path returns a plain error that would break a Cause walk, whether your logging already captures stack information from another source, and which Go version you build against, given the presence of go113.go in the repository. The Makefile's check target is a reasonable model for how the maintainers validate changes, but reproducing staticcheck, misspell, unconvert, ineffassign, unparam and errcheck is your decision, not a requirement of the library.

Editorial conclusion

Adopt pkg/errors if your codebase predates Go 1.13 error wrapping and you need stack traces attached to errors at the point of failure. Do not adopt it for new code that can use fmt.Errorf with %w and errors.Is/errors.As, because the project itself is in maintenance mode and is not accepting proposals for new functionality. Before committing, verify that your Go version and your error-inspection code match what the library provides: the README documents errors.Wrap, errors.Cause and a causer interface, and the repository contains go113.go, so check how that file interacts with your existing error checks.

Frequently asked questions

How do I install pkg/errors?

The README gives one command, `go get github.com/pkg/errors`, run from your module directory. After that you import the package at that same path and call errors.Wrap or errors.Cause as needed.

Is pkg/errors still maintained?

The README states the package is moving into maintenance mode because of the Go 2 error proposals. It is not accepting proposals for new functionality, though pull requests, bug fixes and issue reports are welcome.

What is the difference between errors.Wrap and errors.Cause in pkg/errors?

Wrap returns a new error that adds context to the original, building a chain. Cause reverses that operation by recursively retrieving the topmost error that does not implement the causer interface, which is assumed to be the original cause.

What licence does pkg/errors use?

The licence is BSD-2-Clause, as stated in the README and shown by the LICENSE file at the top level of the repository. Check that file for the exact terms.

Official sources

  1. License: BSD-2-Clause
  2. pkg/errors on GitHub
  3. Project website
  4. README
  5. Releases
For maintainers

Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/pkg-errors.svg)](https://hysenlabs.com/projects/pkg-errors)
Community notes

Community notes