Error Types
There are various options for declaring errors:
errors.New
for errors with simple static stringsfmt.Errorf
for formatted error strings- Custom types that implement an
Error()
method Wrapped errors using
"pkg/errors".Wrap
When returning errors, consider the following to determine the best choice:Is this a simple error that needs no extra information? If so,
errors.New
should suffice.- Do the clients need to detect and handle this error? If so, you should use acustom type, and implement the
Error()
method. - Are you propagating an error returned by a downstream function? If so, checkthe section on error wrapping.
- Otherwise,
fmt.Errorf
is okay. If the client needs to detect the error, and you have created a simple errorusingerrors.New
, use a var for the error.
Bad | Good |
---|---|
|
|
If you have an error that clients may need to detect, and you would like to addmore information to it (e.g., it is not a static string), then you should use acustom type.
Bad | Good |
---|---|
|
|
Be careful with exporting custom error types directly since they become part ofthe public API of the package. It is preferable to expose matcher functions tocheck the error instead.
- // package foo
- type errNotFound struct {
- file string
- }
- func (e errNotFound) Error() string {
- return fmt.Sprintf("file %q not found", e.file)
- }
- func IsNotFoundError(err error) bool {
- _, ok := err.(errNotFound)
- return ok
- }
- func Open(file string) error {
- return errNotFound{file: file}
- }
- // package bar
- if err := foo.Open("foo"); err != nil {
- if foo.IsNotFoundError(err) {
- // handle
- } else {
- panic("unknown error")
- }
- }