===== 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. ==== Related pages ==== * [[go:errors:error_wrapping|Error wrapping (%w)]] * [[go:errors:errors_is_as|errors.Is / errors.As]] * [[go:errors:sentinel_errors|Sentinel errors]] ==== 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 * **preserve** /prɪˈzɝːv/: giữ lại * **layer** /ˈleɪər/: tầng