feat: typed decode and encode errors with the key path

Assisted-by: GLM 5.3 Flash
This commit is contained in:
2026-09-17 21:20:47 +02:00
parent 1e3198c8b6
commit 3f41266710
7 changed files with 219 additions and 18 deletions
+28 -4
View File
@@ -404,6 +404,27 @@ if se, ok := errors.AsType[*interpres.SyntaxError](err); ok {
}
```
### `type DecodeError struct{ Path []string; Err error }`
Wraps a decoding failure with the key path at which it happened. `Path` lists
one segment per level from the document root, the outermost key first: a key
contributes its name, an array element its bracketed index, so the path of the
`weight` field in the first item reads `["items", "[0]", "weight"]`. The
rendered message is unchanged by the type; read the fields instead of parsing
the message:
```go
if de, ok := errors.AsType[*interpres.DecodeError](err); ok {
fmt.Println(de.Path, de.Err)
}
```
### `type EncodeError struct{ Path string; Err error }`
Wraps an encoding failure with the key path of the value that failed, in the
document's own notation: `server.ports[2]`. Read it with `errors.AsType` the
same way.
### `type Decoder`
Configurable strictness for decoding, constructed with `NewDecoder`. Set up
@@ -460,11 +481,14 @@ types are produced by `Parse` and accepted by `Marshal`.
The entry points return:
- `*SyntaxError` for a malformed document, with the 1-based line
- a plain error for everything else: a non-pointer decode target, a type
mismatch, an overflow, a marshal policy violation, a cancelled context
- `*DecodeError` for a decoding failure, with the key path in `Path`
- `*EncodeError` for an encoding failure, with the key path in `Path`
- a plain error for the rest: a non-pointer decode target, a cancelled
context, a key that is not valid UTF-8
Decode and encode failures are wrapped with the key path or element index using
`fmt.Errorf`, so `errors.Is` and `errors.AsType` see through them.
Decode and encode failures carry the key path or element index in the typed
wrappers above, so `errors.Is` and `errors.AsType` see through them and the
path reads from a field instead of the message text.
## Notes