Error wrapping means adding context to an error while keeping the original error inside it.
In Go, `fmt.Errorf` supports wrapping using `%w`:
fmt.Errorf("doing X: %w", err)
if err := dbCall(); err != nil { return fmt.Errorf("update user: %w", err) }
In `fmt.Errorf`, you can use:
package main import ( "errors" "fmt" ) var ErrNotFound = errors.New("not found") func repo() error { return ErrNotFound } // Wrap with %w (keeps original error) func usecaseWrap() error { if err := repo(); err != nil { return fmt.Errorf("usecase (wrap): %w", err) } return nil } // Format only with %v (does NOT wrap) func usecaseFormatOnly() error { if err := repo(); err != nil { return fmt.Errorf("usecase (format only): %v", err) } return nil } func main() { errW := usecaseWrap() errV := usecaseFormatOnly() fmt.Println("== %w ==") fmt.Println("Error:", errW) fmt.Println("errors.Is(errW, ErrNotFound):", errors.Is(errW, ErrNotFound)) fmt.Println("\n== %v ==") fmt.Println("Error:", errV) fmt.Println("errors.Is(errV, ErrNotFound):", errors.Is(errV, ErrNotFound)) }
== %w == Error: usecase (wrap): not found errors.Is(errW, ErrNotFound): true == %v == Error: usecase (format only): not found errors.Is(errV, ErrNotFound): false