Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

proposal: Go 2: add a Causer interface for errors #27020

darkfeline opened this Issue Aug 16, 2018 · 3 comments


None yet
4 participants
Copy link

darkfeline commented Aug 16, 2018

This proposal is for adding a new Causer interface for errors to the standard library to address the problem of error propagation through multiple packages. (This idea is inspired by the causer interface in the package.)

Consider three packages A, B, and C, where package A calls a function in package B and that function calls a function in package C. The general problem that this proposal addresses is how should package B propagate an error from package C back to package A.

There are three ways B could handle an error returned from C:

  1. B could return the error directly.
  2. B could return its own error, which exposes the error from package C by:
    a. extracting some information from the error (e.g. fmt.Errorf("blah blah: %s", err))
    b. embedding the original error (e.g. errors.Wrap).

Approach 1 neglects to add context, which could make it hard for package A to interpret the error. Approach 2a includes context from package B, but partially destroys information from the original error. Approach 2b is the most versatile, allowing package B to provide context while preserving the original error.

The problem with approach 2a currently is that there is no standard way to embed an error, and this is really something that benefits from a blessed interface that the Go ecosystem can then agree to use.

The interface is simple:

type Causer {
    Cause() error

Example usage:

// Wrap returns a Causer with Cause set to the given error.
func Wrap(err error, msg string) error {}

// Cause recursively tests for Causer and calls Cause and returns the
// original error.
func Cause(e error) error {}

func Frob() error {
	err := RetryTemporaryErrors(doRequest())
	if err != nil {
		orig := Cause(err)
		if orig, ok := orig.(Timeout); ok && orig.Timeout() {
			fmt.Println("Server is down")
		} else {
			fmt.Printf("Something weird happened: %s\n", orig)
	return nil

func RetryTemporaryErrors(f func() error) error {
	for {
		err := f()
		if err == nil {
			return nil
		if err, ok := err.(Temporary); !(ok && err.Temporary()) {
			return Wrap(err, "not temporary error")
		err = fiddleThing()
		if err != nil {
			return err
		time.Sleep(10 * time.Second)

When I was almost done writing this, I found #25675 which appears to be suggesting something similar. However, this proposal is drastically narrower in scope (just about the Causer interface) and the rationale is that this really needs to be standardized to be useful since it is a problem with how errors cross package boundaries.

@gopherbot gopherbot added this to the Proposal milestone Aug 16, 2018

@gopherbot gopherbot added the Proposal label Aug 16, 2018

@ALTree ALTree changed the title Proposal: Add a Causer interface for errors proposal: Add a Causer interface for errors Aug 16, 2018

@ianlancetaylor ianlancetaylor changed the title proposal: Add a Causer interface for errors proposal: Go 2: add a Causer interface for errors Aug 16, 2018

@ianlancetaylor ianlancetaylor added the Go2 label Aug 16, 2018


This comment has been minimized.

Copy link

ianlancetaylor commented Aug 16, 2018

I'm going to mark this as Go 2 because it should be considered in conjunction with other discussions about error handling for Go 2. We should have a coherent overhaul of error handling, not an incremental approach.

CC @neild @jba


This comment has been minimized.

Copy link

jimmyfrasche commented Aug 24, 2018

It would probably suffice to add a Cause() error method to all types that wrap another error in the stdlib.


This comment has been minimized.

Copy link

ianlancetaylor commented Oct 2, 2018

I think this can be subsumed into the general discussion of errors-as-values: . Closing in favor of that general discussion.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.