Golang / GoLang Production Patterns and Web Standards Interview Questions
How do you wrap errors in Go 1.13+ and use errors.Is and errors.As for inspection?
Go 1.13 introduced the %w verb in fmt.Errorf and the errors.Is / errors.As functions to create and inspect error chains. Wrapping preserves the original error while adding context — callers can still check for specific error types or sentinel values anywhere in the chain.
import "errors" // Sentinel errors â comparable with errors.Is var ( ErrNotFound = errors.New("not found") ErrPermission = errors.New("permission denied") ) // Wrapping with %w â preserves the error chain func fetchUser(id int) (*User, error) { u, err := db.QueryUser(id) if err != nil { return nil, fmt.Errorf("fetchUser(id=%d): %w", id, err) } return u, nil } // errors.Is â checks the entire chain for a target value err := fetchUser(42) if errors.Is(err, ErrNotFound) { http.Error(w, "user not found", http.StatusNotFound) return } // Custom structured 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 validateAge(age int) error { if age < 0 { return fmt.Errorf("validateAge: %w", &ValidationError{Field: "age", Message: "must be non-negative"}) } return nil } // errors.As â extracts a specific error type from the chain var ve *ValidationError if errors.As(err, &ve) { http.Error(w, fmt.Sprintf("invalid field %s: %s", ve.Field, ve.Message), http.StatusBadRequest) } // errors.Unwrap â one level of unwrapping inner := errors.Unwrap(err) // returns the wrapped error // Go 1.20+: errors.Join â wrap multiple errors in one combined := errors.Join(err1, err2) errors.Is(combined, err1) // true
Key difference: %v formats the error as a plain string — the wrapped error is lost for inspection purposes. %w both formats it AND preserves the wrapped error so errors.Is and errors.As can traverse the chain.
More Related questions...