errors
errors copied to clipboard
Proposal/Question: Type assertions on the entire error stack
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
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?
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.
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.
@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.
Related proposed solution: https://github.com/pkg/errors/issues/144
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.
@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.
I think this is addressed with standard errors.As.