pkg / errors

Simple error handling primitives
https://godoc.org/github.com/pkg/errors
BSD 2-Clause "Simplified" License
8.18k stars 691 forks source link

Elegant way to check error is wrapped #243

Closed richzw closed 3 years ago

richzw commented 3 years ago

We have one function that returns errors one of them is wrapped by errors.Wrap(), the others are not.

var ErrTest1 = errors.New("error test 1")
var ErrTest2 = errors.New("error test 2")
var ErrRPC = errors.New("error rpc")

func rpcCall() error {
    return ErrRPC
}

func testErrWrap(a int) error {
    if a == 1 {
        return ErrTest1
    } else if a == 2 {
        return ErrTest2
    } else {
        err := rpcCall()
        if err != nil {
            return errors.Wrap(ErrRPC, "call rpc err")
        }
    }
    return nil
}

We have two solutions, one is

    err := testErrWrap(3)

    if errors.Unwrap(err) != nil {
        fmt.Println(errors.Unwrap(err))
    }

the other is

    err := testErrWrap(3)

    if !errors.Is(err, ErrTest2) && !errors.Is(err, ErrTest1) {
        tErr := errors.Unwrap(err)
        fmt.Println(tErr)
    }

We want to know the elegant way to distinguish errors are wrapped or not in Go?

davecheney commented 3 years ago

I think the former is better.

puellanivis commented 3 years ago

Also consider testing for behavior:

err := testErrWrap(3)

var wrappedErr interface { Unwrap() error }
if errors.As(err, &wrappedErr) {
    fmt.Println(errors.Unwrap(err))
}

But also of note, errors.Wrap(…) double wraps your error: one WithMessage and one WithStack. So using errors.Unwrap(err) on the error from errors.Wrap(ErrRPC, "call rpc err") will not give you ErrRPC.

richzw commented 3 years ago

@puellanivis , it seems the fmt.Println(errors.Cause(err)) could print the original error, and the output is error rpc

puellanivis commented 3 years ago

Yes, errors.Cause will strip out all wrapping done with this package, and any other error wraps that implement interface{ Cause() error } though since a lot of packages are switching to native errors with fmt.Errorf("%w", err) wrapping, this won’t help you there.