Golang: How to handle Errors in v1.13

Felipe Dutra Tine e Silva
2 min readSep 5, 2019

--

Golang 1.13 is already released, and you can see on the release notes that there are news on the errors package. So let’s explore that.

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.

What does it means. Lets begin with the new functionality of fmt.Errorf

fmt.Errorf %w

Before to wrap an error in order to add more context we had 2 solutions :

using the excellent package https://github.com/pkg/errors written by M Dave Cheney.

return errors.Wrap(err, "adding more context")

or

return fmt.Errorf("adding more context: %v", err)

Now you can also use :

return fmt.Errorf("adding more context: %w", err)

this one will have the advantage to work with the new 2 functions errors.Is and errors.As.

The problem before with fmt.Errorf and %v is that you lost the error information, and you can’t anymore do (playground):

var e1 = errors.New("Error 1")func x() error {
return fmt.Errorf("adding more context: %v", e1)
}
func main() {
e := x()
if e == e1 {// DOES NOT WORK,you loose the ability to compare errors
// handle gracefully
fmt.Println("WORKS?")
}
}

errors.Is

But if you use %w with the new errors.Is function (playground) :

var e1 = errors.New("Error 1")func x() error {
return fmt.Errorf("adding more context: %w", e1)
}
func main() {
e := x()
if errors.Is(e, e1) {// Magical it works
// handle gracefully
fmt.Println("WORKS")
}
}

errors.As

You can aswell extract the error from the wrapping with the errors.As function (playground) :

type myError struct {  
err string
more string
}
func (e *myError) Error() string {
return fmt.Sprintf("%s: %s", e.more, e.err)
}
func x() error {
return fmt.Errorf("adding more context: %w", &myError{"error", "more"})
}
func main() {
e := x()

var err *myError
if ok := errors.As(e, &err); ok {
// handle gracefully
fmt.Println(err.more)
}
}

But the errors.As function only works with an interface or a type implementing error (not error directly) like :

    // THIS CODE DOES NOT COMPILE
var err *error
if ok := errors.As(e, &err); ok { // COMPILATION ERROR
// handle gracefully
fmt.Println(err)
}

Links :

--

--