Catching Go errors with errors.Is()
Tags: go, errors
Published: 2023-02-11 08:46:03

---
title: Catching Go errors with errors.Is()
published: true
description: Catching Go errors with errors.Is()
tags: go,errors
canonical_url: https://tomdeneire.medium.com/catching-go-errors-with-errors-is-a88c58582bfe
---

![Photo by [David Pupaza](https://unsplash.com/@dav420?utm_source=medium&utm_medium=referral) on [Unsplash](https://unsplash.com?utm_source=medium&utm_medium=referral)](https://cdn-images-1.medium.com/max/12000/0*COSHG9hBnKhiiwUn)
Photo by [David Pupaza](https://unsplash.com/@dav420?utm_source=medium&utm_medium=referral) on [Unsplash](https://unsplash.com?utm_source=medium&utm_medium=referral)

## Go error handling

Anyone who has done some development in Go will be familiar with the Go philosophy on error handling and the following pattern:

    result, err := myFunc(args)
     if err != nil {
      // do something
     }

## Catching errors

As many Gophers, over time I have grown accustomed to the inevitability of Go’s errors and come to appreciate this explicit and sturdy way of handling errors. Up till recently, however, there was one aspect about Go errors that kept confusing me, namely how to catch *specific *errors.

Let’s look at the following example:

    file, err := os.Open("myfile")
       if err != nil {
           // handle error
    }

In a case like this, coming from a Python background, I would like to use *try…catch…* pattern, for instance, to create myfile should it not exist.

In idiomatic Go there are two solutions for this.

The first is to rewrite the code to first check whether the file exists (you can use os.Stat() for that) and, if not, create it — this is probably preferable in this case.

The second is to make use of errors.Is() — this can be used if there is no workaround (see below).

## errors.Is()

Go’s error package has a function [errors.Is()](https://pkg.go.dev/errors#Is)that enables you to test a certain error against a *target*, like so:
{% gist https://gist.github.com/TomDeneire/4d9e5dd094178396ffbccdc72df742a6.js %}
In this way, we are able to catch a specific case of the possible errors returned by os.Open() , namely “file does not exist”, as different from, for instance, “permission denied”.


However, it can be a bit tricky to find the correct target to test an error against. Whereas other languages like Python will print a specific code in the error output (in this case [FileNotFoundError](https://docs.python.org/3/library/exceptions.html#FileNotFoundError)) which you can then use as an exception, Go will only print the string representation of the error:

    open myfile: no such file or directory

In Go you can either test against errors you define yourself, or generic system errors, like the ones defined in package [io/fs](https://pkg.go.dev/io/fs#pkg-variables) :

    var (
    	ErrInvalid    = errInvalid()    // "invalid argument"
    	ErrPermission = errPermission() // "permission denied"
    	ErrExist      = errExist()      // "file already exists"
    	ErrNotExist   = errNotExist()   // "file does not exist"
    	ErrClosed     = errClosed()     // "file already closed"
    )

Another case where these predefined error variables are useful, is the [sql](https://pkg.go.dev/database/sql#pkg-variables) package, as even “no rows found” is an error in Go:

    var ErrNoRows = errors.New("sql: no rows in result set")

This is a clear example of where you cannot work around the error and would want to specifically test it, since you would like to catch “no rows”, but still have the software fail at something like a connection error! Just have a look at an an example from the documentation:
{% gist https://gist.github.com/TomDeneire/d27c16cf3b93a7a0788b3abb5329c2ce.js %}
## errors.As()

Finally, there is also another function, [errors.As()](https://pkg.go.dev/errors#As) ,which lets you use the error target:
{% gist https://gist.github.com/TomDeneire/c5503dd96596b352f5119e665502912f.js %}
Output:

    Failed at path: non-existing

For more information on this advanced variation of the pattern, have a look at the [documentation](https://pkg.go.dev/errors#As)!

---
*Hi! 👋 I’m Tom. I’m a software engineer, a technical writer and IT burnout coach. If you want to get in touch, check out [https://tomdeneire.github.io](https://tomdeneire.github.io/)*