Go

What does fmt.Errorf("op: %w", err) return when err is nil? Why does this matter in helper functions?

Question 319HardGo 1.22 to 1.25

It returns a non-nil error whose message is op: %!w(<nil>). fmt.Errorf always returns a new error value, and it doesn't care whether the operand is nil. So an unconditional "wrap" helper turns success into failure.

func wrap(op string, err error) error {
	return fmt.Errorf("%s: %w", op, err) // BUG when err == nil
}

func wrapSafe(op string, err error) error {
	if err == nil {
		return nil
	}
	return fmt.Errorf("%s: %w", op, err)
}

func main() {
	fmt.Println(wrap("save", nil) == nil)     // false
	fmt.Println(wrap("save", nil))            // save: %!w(<nil>)
	fmt.Println(wrapSafe("save", nil) == nil) // true
}

A common pattern is to decorate every error a function returns, using a defer:

func Save(u User) (err error) {
	defer func() {
		if err != nil {
			err = fmt.Errorf("save user %d: %w", u.ID, err)
		}
	}()
	// ...
	return nil
}

This pattern depends on named results. The err != nil guard is what keeps the nil case correct.

More on Error Handling & panics

All 37 Error Handling & panics questions