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

Proposal/Question: Type assertions on the entire error stack #88

Open
sheenobu opened this issue Oct 23, 2016 · 8 comments
Open

Proposal/Question: Type assertions on the entire error stack #88

sheenobu opened this issue Oct 23, 2016 · 8 comments

Comments

@sheenobu
Copy link

Originally, checking if a error matches a given interface, you would simply m, ok := err.(myInterface). With pkg/errors, it's now m, ok := errors.Cause(err).(myInterface) (Basing this off of the writing here: http://dave.cheney.net/2016/04/27/dont-just-check-errors-handle-them-gracefully)

However, this falls apart if your error stack has myInterface in the middle, since errors.Cause(err).(myInterface) only checks the bottom of the stack:

err := errors.New("Sample error")
// because myCodedError is in the middle of a stack, we have no way
// of getting at Code without writing a custom function that is a near 
// clone of errors.Cause()
err = &myCodedError{code: 404, err: err}
err = Wrap(err, "Wrapping 1")
err = Wrap(err, "Wrapping 2")
err = Wrap(err, "Wrapping 3")

Question: What is the best way to handle this? Custom functions for each of your interfaces which may
get paired with a causer. A generalized function added to pkg/errors?

I've thrown up some code here which shows the varying cases and solutions https://play.golang.org/p/E8eJeWbOuV

@davecheney
Copy link
Member

errors.Cause always unwraps as far as it can, ie to the bottom of the stack, or at least until you hit an error which does not implement Cause.

What is it you want to do? Do you want to recover &myCodedError? If so, dont' have it implement Cause and it will become the result of errors.Cause?

@sheenobu
Copy link
Author

errors.Cause always unwraps as far as it can, ie to the bottom of the stack, or at least until you hit an error which does not implement Cause.

That's understood. It's that the stack of errors lose all type information except for the one on the top and the one at the bottom.

What is it you want to do? Do you want to recover &myCodedError? If so, dont' have it implement Cause and it will become the result of errors.Cause?

That is a solution but it becomes a mandate that error types with Cause methods can only have Cause methods.

@danilobuerger
Copy link

danilobuerger commented Mar 4, 2017

I am wondering the same thing. Reading through @davecheney article https://dave.cheney.net/2016/04/27/dont-just-check-errors-handle-them-gracefully the advice is to use behavior. If the behavior is somewhere in the middle of the stack and that error implements Cause, I currently don't have a way to easily get that via this pkg. I would have to implement my own unwind.

@sheenobu
Copy link
Author

sheenobu commented Mar 4, 2017

@danilobuerger My original post has a generalized but not optimal Recurse method for unwinding. I'm still wavering on a design, though, which wraps both this issue and key-value logging concerns.

@jaekwon
Copy link

jaekwon commented Dec 30, 2017

Related proposed solution: #144

@puellanivis
Copy link

How would any of you propose to assert the entire wrapped error stack?

Without reflect you cannot pass an interface type for it to be tested again, so each and every attempt to assert against any interface would have to for-loop through the errors.

If you want to task to each person the interface matching on each error in the cause chain… you can already do that, because you can type assert yourself in your own code.

There is no way within the bounds of go lang at this time to do any thing about making this less difficult or arduous an adventure.

@jaekwon
Copy link

jaekwon commented Jan 3, 2018

@puellanivis

Without reflect you cannot pass an interface type for it to be tested again, so each and every attempt to assert against any interface would have to for-loop through the errors.

Right, that's why #144 suggests making errors.Wrap() error return the same error instead of creating a new one if it's already wrapped. That makes it unnecessary to check the whole chain -- the programmer should know exactly how many times to unwrap, and it's typically just once.

@mitar
Copy link

mitar commented Nov 30, 2021

I think this is addressed with standard errors.As.

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

6 participants