User Tools

Site Tools


go:errors:error_wrapping

This is an old revision of the document!


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?

  • Add helpful context at each layer (repo → usecase → handler).
  • Preserve the root cause so callers can detect it with `errors.Is/As`.

Example

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

Notes / pitfalls

  • Use `%w` only once in a single `fmt.Errorf` call.
  • Use `%v` if you only want formatting without wrapping.
  • Wrapping enables `errors.Is` and `errors.As` to work through layers.

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

What is it?

In `fmt.Errorf`, you can use:

  • `%w` to wrap an error (keeps the original error inside)
  • `%v` to format an error (string formatting only; does NOT wrap)

Why it matters

  • `%w` enables `errors.Is` / `errors.As` to find the root cause through wrapped layers.
  • `%v` only prints the error message; `errors.Is` will not match the original error.

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

  • Use `%w` when you want callers to detect the original error using `errors.Is/As`.
  • Use `%v` when you only want a formatted message and do not need error matching.

Hard words (English)

  • wrap /ræp/: bọc
  • format /ˈfɔːrmæt/: định dạng
  • root cause /ruːt kɔːz/: nguyên nhân gốc
  • detect /dɪˈtekt/: phát hiện/nhận biết
  • matching /ˈmætʃɪŋ/: so khớp

Hard words (English)

  • wrap /ræp/: bọc
  • preserve /prɪˈzɝːv/: giữ lại
  • root cause /ruːt kɔːz/: nguyên nhân gốc
  • layer /ˈleɪər/: tầng
go/errors/error_wrapping.1767655304.txt.gz · Last modified: by phong2018