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

Closed
darkfeline opened this issue Aug 16, 2018 · 3 comments
Closed

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

darkfeline opened this issue Aug 16, 2018 · 3 comments

Comments

@darkfeline
Copy link
Contributor

@darkfeline 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 https://github.com/pkg/errors 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
@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
Copy link
Contributor

@ianlancetaylor 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

@jimmyfrasche
Copy link
Member

@jimmyfrasche 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.

@ianlancetaylor
Copy link
Contributor

@ianlancetaylor ianlancetaylor commented Oct 2, 2018

I think this can be subsumed into the general discussion of errors-as-values: https://go.googlesource.com/proposal/+/master/design/go2draft-error-inspection.md . Closing in favor of that general discussion.

@golang golang locked and limited conversation to collaborators Oct 2, 2019
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Linked pull requests

Successfully merging a pull request may close this issue.

None yet
5 participants