# Wrapping and Inspecting Errors — Go (Golang)

Source: https://www.skillbyai.com/en/go/e-wrap

> Add context, keep the cause.

## fmt.Errorf %w, errors.Is, errors.As

Add context as errors travel up with `fmt.Errorf("find user %d: %w", id, err)`; `%w` **wraps** the original so it is not lost. `errors.Is(err, target)` checks whether any error in the chain matches a **sentinel** value (like `ErrNotFound` or `fs.ErrNotExist`); `errors.As(err, &target)` finds an error of a specific **type** and gives you its fields. Compare errors with these functions, not with `==` or string matching, so wrapping does not break checks.

## Explicit, wrapped, recoverable

Go treats errors as values, wraps them with context, and reserves panics for truly exceptional situations.

![Three ideas: wrapping and checking errors, defer and recover, error design.](assets/figures/go/section-4-map.svg) — Figure 4.1 — Errors, defer and recovery.

## Sentinel, typed and standard library errors, run

I ran this with Go 1.27.1 (`go run .` in a module named demo, standard library only). The wrapped error keeps its message chain and still matches ErrNotFound; errors.As extracts the ValidationError and its field; opening a missing file matches fs.ErrNotExist.

```go
package main

import (
	"errors"
	"fmt"
	"io/fs"
	"os"
)

var ErrNotFound = errors.New("not found") // sentinel error

type ValidationError struct{ Field string }

func (e *ValidationError) Error() string { return "invalid " + e.Field }

func findUser(id int) error {
	if id <= 0 {
		return &ValidationError{Field: "id"}
	}
	return fmt.Errorf("find user %d: %w", id, ErrNotFound) // wrap with context
}

func main() {
	err := findUser(7)
	fmt.Println(err)
	fmt.Println("is ErrNotFound:", errors.Is(err, ErrNotFound))

	var ve *ValidationError
	err = findUser(-1)
	fmt.Println("as ValidationError:", errors.As(err, &ve), ve.Field)

	_, err = os.Open("missing.txt")
	fmt.Println("file missing:", errors.Is(err, fs.ErrNotExist))
}
```

Output:

```
find user 7: not found
is ErrNotFound: true
as ValidationError: true id
file missing: true
```

## Wrap with context once per layer

Each layer adds what it knows (operation, ids) so the final message reads like a stack of reasons.

**Quiz:** Which verb in fmt.Errorf wraps an error so errors.Is can find it?

- [ ] %e
- [ ] %v
- [ ] %s
- [x] %w

*Answer:* %w. %w preserves the chain.
