How to convert a Panic to Error in Golang?

Panic is basically an unhandled errors which are not anticipated by programmers. You can easily convert these panics to error in golang so that you can recover from these panics more gracefully.

Panics are basically unhandled errors in Golang which are not anticipated by programmers. You can write recovery functions around your code in order to handle these panics more gracefully. There are times when you would want to convert these panics into errors you meet your requirements. So, in this article we will look into how to convert a panic into error in Golang.

Before we start looking into the solution, lets first look into the problem. For this lets take my use case. We have API controller handlers which handle API requests coming to our servers. In these API handlers we make interactions with DB and other internal Services. Since, there are multiple points of failure we want to wrap our API handlers with recovery functions.

Now, I also want to log the error that caused the panic and this is the point where I need to convert panics to error in Golang. The below code replicates somewhat of our use case.

Base Code without Panic Handling

package main

func main() {
  getUserHandler()
}

func getUserHandler() {
  // Make service calls here
  // Also, lets raise a panic
  panic("WTF just happened")
}

func logError(err error) {
  fmt.Println(err)
}

In the above code, we don;‘t have any panic handle at all. When you run the code you see an error in the console with the panic message panic: WTF just happened along with the stacktrace of the error.

Add panic handlers to our code

Now, lets add some panic handlers to the code. By adding a defer recover block, we would be able to capture the error.

func main() {

  defer func() {
    if err := recover(); err != nil {
      fmt.Println(err)
      //logError(err) --> This will throw error as any is not of type error
    }
  }()

  getUserHandler()
}

In the code above we have called recover function in a deferred function. This will make sure that in the case of an unhandled panic we are able to capture the panic that was raised. The err here is of type any.

Convert panic to type error

Now, lets convert this panic to error so that it can be logged using our logger method.

func main() {

  defer func() {
		if err := recover(); err != nil {
			logError(fmt.Errorf("%+v", err))
		}
	}()

  getUserHandler()
}

The above code is going to convert this err from type any to an error type. You can now use it in your code like any error and handle it in a graceful way.