I am checking through an error trace in Go v1.13 Go v1.14. Why does it appear that only error implementations without parameters or with value receivers can be found with errors.Is()? This means that an error implementation capable of wrapping must have a value receiver in order to be able to be found with errors.Is().
package main import ( "fmt" "errors" ) type someAtomicError struct {} func (e *someAtomicError) Error() string { return "Hi!" } func checkAtomicError() { e := &someAtomicError{} e2 := fmt.Errorf("whoa!: %w", e) e2IsE := errors.Is(e2, &someAtomicError{}) fmt.Println("atomic error trace ---\t\t", e2, "\t\t--- is traceable: ", e2IsE) } type someWrapperError struct { Msg string Err error } func (e someWrapperError) Error() string { return fmt.Sprintf("%s: %v", e.Msg, e.Err) } func (e someWrapperError) Unwrap() error { return e.Err } func checkWrapperError() { e := someWrapperError{"Hi!", nil} e2 := fmt.Errorf("whoa!: %w", e) e2IsE := errors.Is(e2, someWrapperError{"Hi!", nil}) fmt.Println("wrapper error trace ---\t\t", e2, "\t--- is traceable: ", e2IsE) } type somePointerWrapperError struct { Msg string Err error } func (e *somePointerWrapperError) Error() string { return fmt.Sprintf("%s: %v", e.Msg, e.Err) } func (e *somePointerWrapperError) Unwrap() error { return e.Err } func checkPointerWrapperError() { e := &somePointerWrapperError{"Hi!", nil} e2 := fmt.Errorf("whoa!: %w", e) e2IsE := errors.Is(e2, &somePointerWrapperError{"Hi!", nil}) fmt.Println("pointer wrapper error trace ---\t", e2, "\t--- is traceable: ", e2IsE) } func main() { checkAtomicError() checkWrapperError() checkPointerWrapperError() } //atomic error trace --- whoa!: Hi! --- is traceable: true //wrapper error trace --- whoa!: Hi!: <nil> --- is traceable: true //pointer wrapper error trace --- whoa!: Hi!: <nil> --- is traceable: false https://play.golang.org/p/-hSukZ-gii2
It seems that any difference in parameters, including in the wrapped error parameter, Err, will result in the type being unable to be found with errors.Is().