go / expert
Snippet
Error Chain Inspection with errors.As and Unwrap
Expert Go error handling layers context around a root cause via fmt.Errorf with %w plus custom types that implement Unwrap(). errors.As walks the chain and copies the first matching typed error into the target pointer, exposing fields like Op and Path. errors.Is walks the same chain comparing against sentinel values. Together they let callers branch on either structural metadata or identity without brittle string matching, and without losing the original error.
snippet.go
go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
package mainimport ("errors""fmt""os")type PathError struct {Op stringPath stringErr error}func (e *PathError) Error() string {return e.Op + " " + e.Path + ": " + e.Err.Error()}func (e *PathError) Unwrap() error { return e.Err }func openConfig() error {return &PathError{Op: "open", Path: "/etc/app.conf",Err: fmt.Errorf("stat: %w", os.ErrNotExist)}}func main() {err := openConfig()var pe *PathErrorif errors.As(err, &pe) {fmt.Println("op:", pe.Op, "path:", pe.Path)}if errors.Is(err, os.ErrNotExist) {fmt.Println("missing — using defaults")}}
Breakdown
1
func (e *PathError) Unwrap() error { return e.Err }
Implementing Unwrap on a pointer receiver hooks PathError into the errors.Is/As traversal so wrapped causes remain inspectable.
2
Err: fmt.Errorf("stat: %w", os.ErrNotExist)
The %w verb wraps the sentinel os.ErrNotExist, producing a two-level chain: PathError → fmt error → os.ErrNotExist.
3
if errors.As(err, &pe) {
errors.As scans the chain and assigns the first *PathError it finds to pe — no type assertion or string parsing needed.
4
if errors.Is(err, os.ErrNotExist) {
errors.Is keeps walking past the PathError layer and matches the deeply wrapped sentinel, enabling clean fallback logic.