Golang / Golang Internals and Memory Management Interview Questions
How does error wrapping work in Go 1.13+ with errors.Is and errors.As?
Go 1.13 introduced a standardised error wrapping API. Errors can be wrapped using fmt.Errorf("... %w", err) to create a chain, and errors.Is / errors.As traverse that chain to find specific errors or extract their values.
import "errors" // Sentinel errors â comparable with == or errors.Is var ErrNotFound = errors.New("not found") var ErrPermission = errors.New("permission denied") // Wrap â %w creates an error chain func openFile(path string) error { if err := os.Open(path); err != nil { return fmt.Errorf("openFile %s: %w", path, err) // wrap with context } return nil } // errors.Is â checks if any error in the chain equals the target err := openFile("/nonexistent") if errors.Is(err, os.ErrNotExist) { fmt.Println("file does not exist") } // Custom error type type ValidationError struct { Field string Message string } func (e *ValidationError) Error() string { return fmt.Sprintf("validation error on %s: %s", e.Field, e.Message) } func validate(name string) error { if name == "" { return fmt.Errorf("user creation: %w", &ValidationError{"name", "required"}) } return nil } // errors.As â extracts a specific type from the chain err = validate("") var ve *ValidationError if errors.As(err, &ve) { fmt.Printf("Field: %s, Message: %s\n", ve.Field, ve.Message) } // errors.Unwrap â one level only inner := errors.Unwrap(err) // returns the wrapped *ValidationError // Multiple wrapping (Go 1.20+) â join multiple errors err1, err2 := errors.New("e1"), errors.New("e2") joined := errors.Join(err1, err2) errors.Is(joined, err1) // true
More Related questions...