Go wraps an error with context while preserving the original cause.

wrapping `fmt.Errorf` with `%w` adds context without discarding the error underneath.

Error Wrapping

operation
error_wrapping.go
Replay: real traced execution (multi-file project)
package main

import (
	"errors"
	"fmt"
)

func main() {
	var operation = "load"
	base := errors.New("config missing")
	wrapped := fmt.Errorf("%s failed: %w", operation, base)

	fmt.Println("operation=", operation)
	fmt.Println("base=", base.Error())
	fmt.Println("has_error=", wrapped != nil)
	fmt.Println("message=", wrapped.Error())
}
package main

import (
	"errors"
	"fmt"
)

func main() {
	var operation = "save"
	base := errors.New("config missing")
	wrapped := fmt.Errorf("%s failed: %w", operation, base)

	fmt.Println("operation=", operation)
	fmt.Println("base=", base.Error())
	fmt.Println("has_error=", wrapped != nil)
	fmt.Println("message=", wrapped.Error())
}
package main

import (
	"errors"
	"fmt"
)

func main() {
	var operation = "delete"
	base := errors.New("config missing")
	wrapped := fmt.Errorf("%s failed: %w", operation, base)

	fmt.Println("operation=", operation)
	fmt.Println("base=", base.Error())
	fmt.Println("has_error=", wrapped != nil)
	fmt.Println("message=", wrapped.Error())
}
  1. operation ← "load", base ← &errors.errorString{s:"config missing"}

    8func main() {9  var operation→ "load" = "load" //@operation="save", "delete"10  base→ &errors.errorString{s:"config missing"} := errors.New("config missing")11  wrapped→ &fmt.wrapError{msg:"load failed: config missing", err:(*errors.errorString)(⟨addr A⟩)} := fmt.Errorf("%s failed: %w", operation"load", base&errors.errorString{s:"config missing"})1213  fmt.Println("operation=", operation"load")14  fmt.Println("base=", base&errors.errorString{s:"config missing"}.Error())15  fmt.Println("has_error=", wrapped&fmt.wrapError{msg:"load failed: config missing", err:(*errors.errorString)(⟨addr A⟩)} != nil)16  fmt.Println("message=", wrapped&fmt.wrapError{msg:"load failed: config missing", err:(*errors.errorString)(⟨addr A⟩)}.Error())17}
    outputoperation= load
    base= config missing
    has_error= true
    message= load failed: config missing
  1. operation ← "save", base ← &errors.errorString{s:"config missing"}

    8func main() {9  var operation→ "save" = "save"10  base→ &errors.errorString{s:"config missing"} := errors.New("config missing")11  wrapped→ &fmt.wrapError{msg:"save failed: config missing", err:(*errors.errorString)(⟨addr A⟩)} := fmt.Errorf("%s failed: %w", operation"save", base&errors.errorString{s:"config missing"})1213  fmt.Println("operation=", operation"save")14  fmt.Println("base=", base&errors.errorString{s:"config missing"}.Error())15  fmt.Println("has_error=", wrapped&fmt.wrapError{msg:"save failed: config missing", err:(*errors.errorString)(⟨addr A⟩)} != nil)16  fmt.Println("message=", wrapped&fmt.wrapError{msg:"save failed: config missing", err:(*errors.errorString)(⟨addr A⟩)}.Error())17}
    outputoperation= save
    base= config missing
    has_error= true
    message= save failed: config missing
  1. operation ← "delete", base ← &errors.errorString{s:"config missing"}

    8func main() {9  var operation→ "delete" = "delete"10  base→ &errors.errorString{s:"config missing"} := errors.New("config missing")11  wrapped→ &fmt.wrapError{msg:"delete failed: config missing", err:(*errors.errorString)(⟨addr A⟩)} := fmt.Errorf("%s failed: %w", operation"delete", base&errors.errorString{s:"config missing"})1213  fmt.Println("operation=", operation"delete")14  fmt.Println("base=", base&errors.errorString{s:"config missing"}.Error())15  fmt.Println("has_error=", wrapped&fmt.wrapError{msg:"delete failed: config missing", err:(*errors.errorString)(⟨addr A⟩)} != nil)16  fmt.Println("message=", wrapped&fmt.wrapError{msg:"delete failed: config missing", err:(*errors.errorString)(⟨addr A⟩)}.Error())17}
    outputoperation= delete
    base= config missing
    has_error= true
    message= delete failed: config missing