I would like to return any panic as an error value in a function. Is it safe to assume that all panics are of type error (Example A) or do I need to tread them as strings (Example B) or something else?
func API() (err error) {
defer func() {
if r := recover(); r != nil {
err = r.(error)
}
}()
mayPanic()
return
}
func API2() (err error) {
defer func() {
if r := recover(); r != nil {
err = fmt.Errorf("%s", r)
}
}()
mayPanic()
return
}
In my tests both examples create the same output for panics, but there may be cases I am missing.
No. It's the type of whatever argument was supplied to the panic
call that you are now recovering. In fact, the return value of recover
is the same value supplied to panic
.
Go specs: https://go.dev/ref/spec#Handling_panics
When the running of deferred functions reaches D [a function D that calls recover], the return value of D's call to
recover
will be the value passed to the call ofpanic
.
You can't assume that all recovered values are error
s, unless you are in full control of your code and somehow enforce passing error
s to panic
calls.
If the code you're dealing with could pass arbitrarily typed values to panic
, you should test for its type when recovering it:
func API() (err error) {
defer func() {
if r := recover(); r != nil {
if err2, ok := r.(error); ok {
err = err2 // or some other error wrapping
} else {
err = fmt.Errorf("recovered panic: %v", r)
}
}
}()
mayPanic()
return
}