Go's approach to error handling is based on two ideas:
Errors are an important part of an application's or library’s interface.
Failure is just one of several expected behaviors.
Thus, errors are values, just like any other values returned by a function. You should therefore pay close attention to how you create and handle them.
Some functions, like strings.Contains or strconv.FormatBool, can never fail. If a function can fail, it should return an additional value. If there's only one possible cause of failure, this value is a boolean:
If the failure can have multiple causes, the return value is of type error:
The simplest way to create an error is by using fmt.Errorf (or errors.New if no formatting is needed):
But since the error type is an interface
any type that implements a method with the signature Error() string is considered an error.
Error-handling strategies
So, how should you handle errors? Here are five strategies, roughly sorted by frequency of use.
1a) Propagate the error to the caller as-is
1b) Propagate the error to the caller with additional information
When the error eventually reaches the program's main function, it should present a clear causal chain, similar to this NASA accident investigation:
2) Retry if the error is transient
3) Stop the program gracefully (usually from the main package)
or, even better:
4) Log the error and continue (possibly with reduced functionality)
5) Safely ignore the error (rare, but sometimes appropriate)
Distinguishing between errors
Sometimes it's helpful to distinguish between different kinds of errors, not just whether an error occurred. For example, you might want to list files for which you lack permissions. The fs package defines several errors that can be checked using the errors.Is function: