How to Wrap Error in Go: Simple Guide with Examples
In Go, you can wrap errors using
fmt.Errorf with the %w verb or the errors.Wrap function from external packages. Wrapping adds context to the error while preserving the original error for inspection.Syntax
Use fmt.Errorf with %w to wrap an existing error with a new message. The %w verb tells Go to wrap the original error inside the new one.
Example syntax:
fmt.Errorf("new message: %w", originalError)go
err := errors.New("original error") wrappedErr := fmt.Errorf("additional context: %w", err)
Example
This example shows how to wrap an error returned from a function and then check the original error using errors.Is.
go
package main import ( "errors" "fmt" ) func readFile() error { return errors.New("file not found") } func loadConfig() error { err := readFile() if err != nil { return fmt.Errorf("loadConfig failed: %w", err) } return nil } func main() { err := loadConfig() if err != nil { fmt.Println("Error:", err) if errors.Is(err, errors.New("file not found")) { fmt.Println("Cause: file not found error detected") } else { fmt.Println("Cause: unknown error") } } }
Output
Error: loadConfig failed: file not found
Cause: unknown error
Common Pitfalls
A common mistake is to wrap errors without using %w, which prevents unwrapping and checking the original error.
Also, comparing errors directly with == often fails because wrapped errors are different objects.
go
package main import ( "errors" "fmt" ) func badWrap() error { err := errors.New("original error") // Wrong: no %w, so error is not wrapped properly return fmt.Errorf("context: %v", err) } func goodWrap() error { err := errors.New("original error") // Correct: %w wraps the error return fmt.Errorf("context: %w", err) } func main() { origErr := errors.New("original error") badErr := badWrap() goodErr := goodWrap() fmt.Println("badWrap error:", badErr) fmt.Println("goodWrap error:", goodErr) // This will be false because badWrap does not wrap properly fmt.Println("badWrap is original error:", errors.Is(badErr, origErr)) // This will be false too because errors.New creates a new error instance // Correct way is to save original error in a variable wrappedErr := fmt.Errorf("context: %w", origErr) fmt.Println("goodWrap is original error:", errors.Is(wrappedErr, origErr)) }
Output
badWrap error: context: original error
goodWrap error: context: original error
badWrap is original error: false
goodWrap is original error: true
Quick Reference
- Wrap error:
fmt.Errorf("message: %w", err) - Check error:
errors.Is(err, targetErr) - Retrieve original error:
errors.Unwrap(err)
Key Takeaways
Use fmt.Errorf with %w to wrap errors and preserve the original error.
Always use errors.Is to check if an error wraps a specific original error.
Avoid wrapping errors without %w as it breaks error unwrapping.
Store original errors in variables to compare correctly with errors.Is.
Wrapping errors adds helpful context for debugging while keeping error chains intact.