← Back to Go Course | Chapter 9: Error Handling | Lesson 6 of 6

Wrapping Errors

Wrapping an error is like putting the original problem inside a new envelope with extra notes on the outside, while still letting someone open it back up to see the original note inside.

Wrapping with %w

fmt.Errorf's %w verb, used in place of %v or %s, wraps the given error inside a new one, adding a message prefix while preserving the ability to unwrap back to the original.

Example: Wrapping with %w

markup
package main

import (
	"errors"
	"fmt"
)

func readConfig() error {
	return errors.New("file missing")
}

func startApp() error {
	if err := readConfig(); err != nil {
		return fmt.Errorf("startApp: %w", err)
	}
	return nil
}

func main() {
	fmt.Println(startApp())
}

Checking Through a Wrapped Chain

Even after several layers of wrapping, errors.Is can still detect the original error at the bottom of the chain, letting each layer add context without breaking error identity checks further up the call stack.

Example: Checking Through a Wrapped Chain

markup
package main

import (
	"errors"
	"fmt"
)

var ErrConfigMissing = errors.New("config missing")

func readConfig() error {
	return ErrConfigMissing
}

func startApp() error {
	if err := readConfig(); err != nil {
		return fmt.Errorf("startApp failed: %w", err)
	}
	return nil
}

func main() {
	err := startApp()
	fmt.Println(err)
	fmt.Println("is config missing:", errors.Is(err, ErrConfigMissing))
}

Manually Unwrapping

errors.Unwrap retrieves the single error wrapped one level down, which is the primitive that errors.Is and errors.As use internally to walk the whole chain step by step.

Note: Prefer errors.Is/errors.As in application code -- Unwrap is mostly useful for writing your own error-inspection tools.

Example: Manually Unwrapping

markup
package main

import (
	"errors"
	"fmt"
)

func main() {
	base := errors.New("disk full")
	wrapped := fmt.Errorf("save failed: %w", base)

	inner := errors.Unwrap(wrapped)
	fmt.Println("outer:", wrapped)
	fmt.Println("inner:", inner)
}
Common Mistakes
  1. Using %v instead of %w in fmt.Errorf, which loses the ability for errors.Is/errors.As to see the original wrapped error.
  2. Wrapping the same error many times through several layers, creating an error message so long it becomes unreadable.
  3. Forgetting that wrapping doesn't change what errors.Is/errors.As see -- they still find the originally wrapped sentinel or type.
Chapter Summary
  • fmt.Errorf's %w verb wraps an existing error while adding additional context.
  • A wrapped error still satisfies errors.Is/errors.As checks against the original error.
  • Wrapping preserves the full chain of context as an error travels up through several function calls.
  • Errors.Unwrap can manually retrieve the next error in a wrap chain, though Is/As are usually preferred.
🔒

Chapter Quiz — Complete all 6 topics to unlock

0/6 topics done

Complete these topics first:

Login to run this code

C/C++/Java/PHP execution requires a free account. Your code is saved — you'll land right back in the editor after logging in.