Sentinel error là biến error toàn cục được định nghĩa sẵn, phù hợp cho các điều kiện lỗi đơn giản không cần thêm context. Custom error type phù hợp khi cần mang thêm metadata về lỗi.
go
// Sentinel errors — so sánh bằng errors.Is
var (
ErrNotFound = errors.New("not found")
ErrUnauthorized = errors.New("unauthorized")
ErrConflict = errors.New("already exists")
)
// Custom error type — truy xuất metadata qua errors.As
type AppError struct {
Code int
Message string
Err error // wrapped underlying error
}
func (e *AppError) Error() string {
return fmt.Sprintf("[%d] %s", e.Code, e.Message)
}
func (e *AppError) Unwrap() error { return e.Err } // quan trọng cho error chain
func getUser(id int) (*User, error) {
user, err := db.Find(id)
if err != nil {
return nil, &AppError{Code: 404, Message: "user not found", Err: ErrNotFound}
}
return user, nil
}
// Caller có thể check cả hai cách
err := getUser(99)
errors.Is(err, ErrNotFound) // true — nhờ Unwrap()
var ae *AppError
if errors.As(err, &ae) {
fmt.Println(ae.Code) // 404
}Nguyên tắc: định nghĩa errors trong package, export chúng để caller dùng errors.Is.
Tránh dùng err.Error() == "..." string comparison.