Error Handling
Table of Contents
Error Handling Strategies tutorial
- When a function call returns an error, it's the caller's responsibility to check it and take appropriate action.
error may be
nil
or non-nil, thatnil
implies success and non-nil implies failure
Consider following options:
To propagate the error, so that a failure in a subroutine becomes a failure of the calling routine. Use
fmt.Errorf
, which formats an error message usingfmt.Sprintf
and returns a newerror
value.genesis: crashed: no parachute: G-switch failed: bad relay orientation
Because error messages are frequently chained together, message strings should not be capitalized and newlines should be avoided.
- To retry the failed operation after some delay, if the failure is transient.
- To report the error and stop the program gracefully. Consider using
log.Fatalf()
, which reports the error and exits the program. To just log the error and then continue.
Even though it is idiomatic to return error
whenever possible, if you think that you can not handle the error, you can use panic()
as follows:
package main
import "os"
func main() {
_, err := os.Create("/tmp/file")
if err != nil {
panic(err)
}
}
When panic()
is called, all deferred functions are called and then the program will be terminated. You can call recover()
during the deferred functional call phase, so that the program won't be terminated. It is generally not recommended to recover some other packages' panic
state.
recover()
reference
How recover()
works discussion
- When
panic()
is executed,go
tries to execute all deferred functions within the callee function before exiting it. - If
go
managed to executerecover()
While executing deferred functions,- It sets the program to a normal state, which means that
panicking
will be no longer propagated. - After executing remaining deferred functions, it just exits the current function by returning the current value of result parameters.
- So, by modifying named result parameters, you can return different values when recovering.
- It sets the program to a normal state, which means that
package main
import "fmt"
func f() (result int) {
defer func() {
// This is the idiomatic way to call `recover()`
if r := recover(); r != nil {
fmt.Println("Recovering")
// Assign a different value to the result parameter
result = -1
}
}()
result = 0
fmt.Println("Before panic()")
panic("Opps!")
fmt.Println("After panic()")
return
}
func main() {
fmt.Println("Before f()")
result := f()
fmt.Println("After f()")
fmt.Println(result)
}
Before f()
Before panic()
Recovering
After f()
-1