error is a built-in interface in Go with a single method: Error() string. Any type implementing this method is an error. Go handles errors through return values — functions return (result, error) and callers should check if err != nil at each call site.
error là một interface được tích hợp sẵn trong Go với một phương thức duy nhất: Error() string. Bất kỳ kiểu nào triển khai phương thức này đều là một error. Cách Go xử lý lỗi là thông qua giá trị trả về — hàm trả về (result, error) và gọi nên kiểm tra if err != nil tại từng điểm gọi.
1package main23import (4 "errors"5 "fmt"6)78// error interface is defined as:9// type error interface {10// Error() string11// }12When propagating errors up the stack, add context with fmt.Errorf and %w (wrap). %w lets you wrap the original error in a new message. This creates an error chain that you can inspect piece by piece using errors.Is and errors.As.
Khi truyền lỗi lên trên trong stack, hãy thêm bối cảnh bằng fmt.Errorf và %w (wrap). %w cho phép bạn bao bọc lỗi gốc trong một thông báo mới. Điều này tạo ra chuỗi lỗi mà bạn có thể kiểm tra từng phần bằng errors.Is và errors.As.
1package main23import (4 "errors"5 "fmt"6 "os"7)89// readConfig reads a config file and returns an error if it fails10func readConfig(path string) (string, error) {11 content, err := os.ReadFile(path)12 if err != nil {errors.Is compares an error to a sentinel error by walking the wrap chain. errors.As searches for an error of a specific type in the chain and extracts it. This allows fine-grained error handling even when errors are wrapped deeply.
errors.Is so sánh một lỗi với một sentinel error bằng cách bước qua chuỗi bao bọc. errors.As tìm kiếm lỗi của một kiểu cụ thể trong chuỗi và trích xuất nó. Cách làm này cho phép xử lý lỗi chi tiết ngay cả khi lỗi được bao bọc sâu.
1package main23import (4 "errors"5 "fmt"6)78// Define sentinel errors at package level9var (10 ErrNotFound = errors.New("resource not found")11 ErrPermissionDenied = errors.New("permission denied")12)Định nghĩa sentinel error ở mức gói (package level) bằng var ErrXxx = errors.New(...). Điều này cho phép người gọi so sánh bằng errors.Is.
For fine-grained error handling, define your own custom error types by implementing the Error() method. Custom error types can contain additional information like status codes, validation fields, etc.
Để xử lý lỗi chi tiết, xác định kiểu lỗi tùy chỉnh của riêng bạn bằng cách triển khai phương thức Error(). Kiểu lỗi tùy chỉnh có thể chứa thông tin bổ sung như mã trạng thái, trường bị xác thực, v.v.
1package main23import (4 "fmt"5)67// Custom error with HTTP status code8type HTTPError struct {9 Code int10 Message string11}12panic is used for truly unrecoverable situations — contract violations or broken invariants. recover() is called in a deferred function to catch a panic and regain control. However, do not use panic/recover for normal control flow — use error types instead.
panic được dùng cho các tình huống thực sự không thể khôi phục — các điều kiện tiên quyết vi phạm hoặc bất biến bị phá vỡ. recover() được gọi trong deferred function để bắt panic và lấy lại kiểm soát. Tuy nhiên, đừng dùng panic/recover cho kiểm soát luồng bình thường — dùng error type thay thế.
1package main23import (4 "fmt"5)67// safeDiv panics on division by zero but recovers gracefully8func safeDiv(a, b int) (result int) {9 defer func() {10 if r := recover(); r != nil {11 fmt.Println("Caught panic:", r)12 result = 0Chỉ dùng panic cho các tình huống thực sự không thể khôi phục (lỗi khởi tạo, vi phạm hợp đồng). Đối với lỗi có thể khôi phục, trả về error type.
When an error occurs at a low level, wrap it with context as you propagate it up. Only handle (log, return to user, etc.) at the boundary of your application — for example in a route handler or main function.
Khi lỗi xảy ra ở mức thấp, bao bọc nó với bối cảnh khi truyền lên. Chỉ xử lý (log, trả về cho người dùng, v.v.) ở ranh giới bên ngoài (edge/boundary) của ứng dụng — ví dụ trong route handler hoặc hàm main.
1package main23import (4 "errors"5 "fmt"6)78// Low-level function — just return error as-is or wrap with context9func readDatabase() (string, error) {10 return "", errors.New("connection failed")11}12- Define sentinel errors at package level for expected error cases: var ErrNotFound = errors.New(...)
Xác định sentinel error tại mức gói cho các trường hợp lỗi dự kiến: var ErrNotFound = errors.New(...)
- Use errors.Is(err, ErrNotFound) to check and handle specific cases
Dùng errors.Is(err, ErrNotFound) để kiểm tra và xử lý các trường hợp cụ thể
- Use custom errors (structs) for errors with extra information (status code, field, etc.)
Dùng lỗi tùy chỉnh (struct) cho lỗi có thêm thông tin (mã trạng thái, trường, v.v.)
Key Takeaways
Điểm Chính
- error is an interface; any type with Error() string method is an errorerror là interface; bất kỳ kiểu nào có phương thức Error() string đều là error
- Use fmt.Errorf with %w to wrap errors with context, creating error chainsDùng fmt.Errorf với %w để bao bọc lỗi với bối cảnh, tạo chuỗi lỗi
- Use errors.Is for sentinel errors and errors.As to extract specific error typesDùng errors.Is cho sentinel error và errors.As để trích xuất kiểu lỗi cụ thể
- panic/recover are for unrecoverable situations; use error types for normal error handlingpanic/recover là cho tình huống không thể khôi phục; dùng error type cho xử lý lỗi bình thường
Practice
Test your understanding of this chapter
What is the standard Go idiom for checking if an operation succeeded or failed?
Thành ngữ chuẩn Go để kiểm tra xem hoạt động có thành công hay thất bại là gì?
What is the purpose of the %w verb in fmt.Errorf?
Mục đích của %w trong fmt.Errorf là gì?
In Go, panic should be used for all error cases to ensure the program stops immediately and safely.
Trong Go, panic nên được dùng cho tất cả các trường hợp lỗi để đảm bảo chương trình dừng lại ngay lập tức và an toàn.
The errors.Is function can detect a sentinel error even if it is wrapped multiple times in an error chain.
Hàm errors.Is có thể phát hiện sentinel error ngay cả khi nó được bao bọc nhiều lần trong chuỗi lỗi.
Complete the error wrapping pattern
Hoàn thành mô hình bao bọc lỗi
func readConfig(path string) (string, error) { content, err := os.ReadFile(path) if err != nil { return "", ("failed to read config: %w", ) } return string(content), nil }