Table of Contents

Error wrapping (%w)

What is it?

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)

What is it used for?

Example

if err := dbCall(); err != nil {
    return fmt.Errorf("update user: %w", err)
}

Notes / pitfalls

Error wrapping (%w) vs formatting (%v)

What is it?

In `fmt.Errorf`, you can use:

Why it matters

Example code

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))
}

Example output

== %w ==
Error: usecase (wrap): not found
errors.Is(errW, ErrNotFound): true

== %v ==
Error: usecase (format only): not found
errors.Is(errV, ErrNotFound): false

Rule of thumb

Hard words (English)