Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to compare Go errors

Tags:

go

I have an error value which when printed on console gives me Token is expired

How can I compare it with a specific error value? I tried this but it did not work:

if err == errors.New("Token is expired") {       log.Printf("Unauthorised: %s\n", err) } 
like image 770
codec Avatar asked Aug 24 '16 10:08

codec


People also ask

How do you compare errors in Go?

Using the Is function of errors package – https://golang.org/pkg/errors/ . Using Is function is preferable to using the equality operator because it checks for equality by unwrapping the first error sequentially and matches it with the target error at each step of unwrap.

How do you check if an error is of a certain type Golang?

If we want to check if a given error matches another specific error, we need to use Is() function from the errors package. If we are interested in whether the error is of a given type, we should call the As() function.

How do you wrap an error in Go?

It does not matter that the error is wrapped. A simple comparison if err == ErrorInternal would give false in this case, so it is generally a better idea to use the errors.Is() function to compare errors equality. Then, we unwrap the error using the errors. Unwrap() and print it to the standard output.

Is Go error handling good?

Go's built-in errors don't contain stack traces, nor do they support conventional try / catch methods to handle them. Instead, errors in Go are just values returned by functions, and they can be treated in much the same way as any other datatype - leading to a surprisingly lightweight and simple design.


Video Answer


2 Answers

Declaring an error, and comparing it with '==' (as in err == myPkg.ErrTokenExpired) is no longer the best practice with Go 1.13 (Q3 2019)

The release notes mentions:

Go 1.13 contains support for error wrapping, as first proposed in the Error Values proposal and discussed on the associated issue.

An error e can wrap another error w by providing an Unwrap method that returns w.
Both e and w are available to programs, allowing e to provide additional context to w or to reinterpret it while still allowing programs to make decisions based on w.

To support wrapping, fmt.Errorf now has a %w verb for creating wrapped errors, and three new functions in the errors package ( errors.Unwrap, errors.Is and errors.As) simplify unwrapping and inspecting wrapped errors.

So the Error Value FAQ explains:

You need to be prepared that errors you get may be wrapped.

If you currently compare errors using ==, use errors.Is instead.
Example:

if err == io.ErrUnexpectedEOF 

becomes

if errors.Is(err, io.ErrUnexpectedEOF) 
  • Checks of the form if err != nil need not be changed.
  • Comparisons to io.EOF need not be changed, because io.EOF should never be wrapped.

If you check for an error type using a type assertion or type switch, use errors.As instead. Example:

if e, ok := err.(*os.PathError); ok 

becomes

var e *os.PathError if errors.As(err, &e) 

Also use this pattern to check whether an error implements an interface. (This is one of those rare cases when a pointer to an interface is appropriate.)

Rewrite a type switch as a sequence of if-elses.

like image 158
VonC Avatar answered Sep 23 '22 03:09

VonC


This answer is for Go 1.12 and earlier releases.

Define an error value in a library

package fruits  var NoMorePumpkins = errors.New("No more pumpkins") 

Do not create errors with errors.New anywhere in the code but return the predefined value whenever error occurs and then you can do the following:

package shop  if err == fruits.NoMorePumpkins {      ... } 

See io package errors for reference.

This can be improved by adding methods to hide the check implementation and make the client code more immune to changes in fruits package.

package fruits  func IsNoMorePumpkins(err error) bool {     return err == NoMorePumpkins }  

See os package errors for reference.

like image 44
Grzegorz Żur Avatar answered Sep 21 '22 03:09

Grzegorz Żur