Using named return variables to capture panics in Go
Tags: go
Published: 2018-03-26 15:41:03

---
title: Using named return variables to capture panics in Go
published: true
description: Sometimes you can't help but call a function that might panic. Rather than letting it blow up your code, learn how to use a deferred function and named return variables in order to capture the result as a standard Go error.
tags: golang, go
canonical_url: https://www.calhoun.io/using-named-return-variables-to-capture-panics-in-go/
---

> *This article was original posted on my website at [calhoun.io](https://www.calhoun.io/using-named-return-variables-to-capture-panics-in-go/)*


This is going to be a short post inspired by Sean Kelly's tweet a while back.

{% twitter 930930423315787776 %}

The goal is to just document and illustrate a situation where named return variables are necessary, so with that said let's just jump right in.

Imagine you are writing some code that uses a function that can panic, and for whatever reason (3rd party lib, backwards compatibility, etc) you can't change that function.

```go
func pressButton() {
  fmt.Println("I'm Mr. Meeseeks, look at me!!")
  // other stuff then happens, but if Jerry asks to
  // remove 2 strokes from his golf game...
  panic("It's gettin' weird!")
}
```

You still need to use that function, but if it panics you want to capture the panic and return it as an error so you write some code like this:

```go
func doStuff() error {
  var err error
  // If there is a panic we need to recover in a deferred func
  defer func() {
    if r := recover(); r != nil {
      err = errors.New("the meeseeks went crazy!")
    }
  }()

  pressButton()
  return err
}
```

*Run it on the Go Playground: <https://play.golang.org/p/wzkjKGqFPL>*

Then you go run your code and... what's this? Your error is `nil` even when the code panics? That's not what we wanted!


## Why does this happen?

While at first it looks like our code is returning the `var err error` that we create at the start of our function, the truth is our program never gets to that line of code. This means it never actually returns that specific `err` variable, and altering it inside of our deferred function ends up being pointless.

Adding a `Println` after the call to `pressButton` but before the return really helps illustrate this:

```go
pressButton()
// Nothing below here gets executed!
fmt.Println("we got here!")
return err
```

*Run it on the Go Playground: <https://play.golang.org/p/Vk0DYs20eB>*


## How do we fix it?

To fix this issue, we can simply use a named return variable.

```go
func doStuff() (err error) {
	// If there is a panic we need to recover in a deferred func
	defer func() {
		if r := recover(); r != nil {
			err = errors.New("the meeseeks went crazy!")
		}
	}()

	pressButton()
	return err
}
```

*Run it on the Go Playground: <https://play.golang.org/p/bqGOroPjQJ>*

The resulting code looks very similar, but by naming our return variable when we declare the function our program will now return the `err` variable even if we never hit the return statement at the end of our `doStuff` function. Because of this minor difference, we can now alter the `err` variable inside of our deferred function and successfully capture the panic.