Error types and values are two ways to create errors in Go.
1import (2 "errors"3 "fmt"4)56// 1. Error values (sentinel errors)7var (8 ErrNotFound = errors.New("not found")9 ErrUnauthorized = errors.New("unauthorized")10 ErrForbidden = errors.New("forbidden")11 ErrInternal = errors.New("internal error")12)1314// 2. Error types (with context)15type NotFoundError struct {16 Resource string17 ID interface{}18}1920func (e *NotFoundError) Error() string {21 return fmt.Sprintf("%s with ID %v not found", e.Resource, e.ID)22}2324// 3. Wrapped errors (chain)25type AppError struct {26 Code string27 Message string28 Err error29}3031func (e *AppError) Error() string {32 return fmt.Sprintf("[%s] %s", e.Code, e.Message)33}3435func (e *AppError) Unwrap() error {36 return e.Err37}3839// Usage40func GetUser(id int) (*User, error) {41 user, err := db.Find(id)42 if err != nil {43 if errors.Is(err, sql.ErrNoRows) {44 return nil, &NotFoundError{45 Resource: "User",46 ID: id,47 }48 }49 return nil, &AppError{50 Code: "DB_ERROR",51 Message: "database query failed",52 Err: err,53 }54 }55 return user, nil56}5758// Checking59user, err := GetUser(42)60if err != nil {61 var notFound *NotFoundError62 if errors.As(err, ¬Found) {63 http.Error(w, notFound.Error(), 404)64 }6566 var appErr *AppError67 if errors.As(err, &appErr) {68 log.Printf("Code: %s, Message: %s", appErr.Code, appErr.Message)69 }70}
Difference: