Go Error Wrapping
Here’s how to wrap errors in Go using the fmt.Errorf()
function with the %w
verb:
import (
"fmt"
"errors"
)
func doSomething() error {
err := someOperation()
if err != nil {
return fmt.Errorf("failed to do something: %w", err)
}
return nil
}
To check if an error is a specific type, you can use:
var originalErr *MyCustomError
if errors.As(err, &originalErr) {
// Handle the specific error type
}
To check if an error wraps a specific error value:
if errors.Is(err, sql.ErrNoRows) {
// Handle the specific error
}
Here’s a more complete example showing error wrapping in practice:
type QueryError struct {
Query string
Err error
}
func (e *QueryError) Error() string {
return fmt.Sprintf("query error: %s: %v", e.Query, e.Err)
}
func (e *QueryError) Unwrap() error {
return e.Err
}
func queryDatabase(query string) error {
err := db.Execute(query)
if err != nil {
return &QueryError{
Query: query,
Err: err,
}
}
return nil
}
func handleRequest() error {
if err := queryDatabase("SELECT * FROM users"); err != nil {
return fmt.Errorf("failed to handle request: %w", err)
}
return nil
}
Key points about error wrapping:
- Use
%w
verb withfmt.Errorf()
to wrap errors errors.Unwrap()
returns the wrapped errorerrors.Is()
checks for specific error values through the entire wrap chainerrors.As()
helps with type assertions through the wrap chain- Custom error types can implement
Unwrap()
method to support wrapping
Would you like me to explain any particular aspect of error wrapping in more detail?