Go

What does this print? (Which side's Is method gets called)

Question 327HardGo 1.22 to 1.25
var ErrNotFound = errors.New("not found")

type NotFoundError struct{ Name string }

func (e *NotFoundError) Error() string { return e.Name + ": not found" }
func (e *NotFoundError) Is(target error) bool { return target == ErrNotFound }

func main() {
	err := fmt.Errorf("load: %w", &NotFoundError{"cfg"})

	fmt.Println(errors.Is(err, ErrNotFound))                  // true
	fmt.Println(errors.Is(ErrNotFound, &NotFoundError{"cfg"})) // false
	fmt.Println(errors.Is(err, &NotFoundError{"cfg"}))        // false
}

errors.Is is not symmetric. It only calls Is on the errors in the first argument's chain, never on the target. Line 1 is true because the *NotFoundError in the chain says it matches ErrNotFound. Line 2 is false because ErrNotFound (an *errorString) has no Is method and is not == to the target. Line 3 is false because the two *NotFoundError values are different pointers, and the custom Is only matches ErrNotFound.

This lets a typed error also "be" a sentinel, so callers can use a cheap errors.Is(err, ErrNotFound) check and still reach the details with errors.As. Keep the argument order straight: always errors.Is(err, target).

More on Error Handling & panics

All 37 Error Handling & panics questions