Cả hai đều in ra chuỗi giống nhau, nhưng %w giữ lại lỗi gốc trong chuỗi unwrap, còn %v chỉ ghép chuỗi và cắt đứt liên kết.
go
var ErrNotFound = errors.New("not found")
e1 := fmt.Errorf("load user %d: %w", id, ErrNotFound)
e2 := fmt.Errorf("load user %d: %v", id, ErrNotFound)
errors.Is(e1, ErrNotFound) // true
errors.Is(e2, ErrNotFound) // false — chỉ còn textNguyên tắc dùng:
- Bọc bằng %w khi tầng trên cần phân biệt loại lỗi để quyết định (trả 404 hay 500, có retry không).
- Mỗi lần bọc chỉ thêm ngữ cảnh của tầng đó (tên thao tác, id), không lặp lại thông tin tầng dưới đã có.
- Dùng %v (hoặc lỗi mới hoàn toàn) khi muốn che chi tiết nội bộ khỏi caller — vd không để lỗi driver DB rò ra ngoài API.
Từ Go 1.20, fmt.Errorf chấp nhận nhiều %w trong một chuỗi định dạng, và errors.Join gộp nhiều lỗi độc lập thành một.