Skip to content
This repository has been archived by the owner on Dec 1, 2021. It is now read-only.

Unwrap doesn't return the base error #223

Open
yaziine opened this issue Feb 13, 2020 · 7 comments
Open

Unwrap doesn't return the base error #223

yaziine opened this issue Feb 13, 2020 · 7 comments

Comments

@yaziine
Copy link

yaziine commented Feb 13, 2020

Wrapping an error with errors.Wrap, unwrapping it with errors.Unwrap returns the whole error and not the base one. Is it intentional?

https://play.golang.org/p/baYpfrrvN35

@davecheney
Copy link
Member

errors.Unwraps only unwraps errors wrapper with errors.Wrap, not fmt.Errorf

@yaziine
Copy link
Author

yaziine commented Feb 17, 2020

Not sure to understand you here.
Do you mean that errors.Unwraps only unwraps errors wrapped with fmt.Errorf instead?

@davecheney
Copy link
Member

davecheney commented Feb 17, 2020

Unwrap is just a wrapper around the stdlib errors package's Unwrap.

https://github.com/pkg/errors/blob/master/go113.go

@aperezg
Copy link
Member

aperezg commented Feb 17, 2020

As @davecheney said the behaviour of the Unwrap in the pkg/errors is the same that the standard library:

https://play.golang.org/p/73xe4gnoXKz

@puellanivis
Copy link

Oh, this might be the source of the confusion: Wrap(…) returns a &withStack{ &withMessage{ … } } and so when one calls Unwrap() on it, one gets the &withMessage{ … } rather than the original message that was put into Wrap(…), which makes it appear like it is not unwrapping, unless you’re printing stack traces: https://play.golang.org/p/x0JN-W_FStu

This ends up being misleading because one would naturally expect err2 := errors.Unwrap(errors.Wrap(err1)) would result in err2 == err1 but it does not, because internally errors.Wrap is actually double wrapping. No one noticed when using Cause(…) because it kept unwrapping until it got to a non-Causer, but errors.Unwrap only unwraps a single layer. 😕

@zhangguanzhang
Copy link

should use errors.Cause(err)
https://play.golang.org/p/L-uJU07lCAu

@puellanivis
Copy link

errors.Cause will repeatedly unwrap all of the pkg/errors wrappings. So we get:

err := stdErrors.New("thing")
err2 := errors.WithMessage(err, "inner wrap")
err3 := errors.Wrap(err, "outer wrap")
cause := errors.Cause(err3)
unwrap := errors.Unwrap(err3)
// (cause == err) == true
// (unwrap != err3 && unwrap != err2 && unwrap != err) == true

There is no way in this scenario to retrieve err2 from err3, and that’s not ideal.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

5 participants