Aggregate errors¶
Join collects several errors into one, and — unlike the library this replaces
— does not lose what is attached to them.
var errs []error
for _, source := range sources {
if err := check(source); err != nil {
errs = append(errs, err)
}
}
return errors.Join(errs...)
Join returns nil when every argument is nil, so the loop above needs no
"were there any" branch.
Everything below it stays readable¶
a := errors.WithHint(errors.New("a failed"), "check A")
b := errors.WithHint(errors.New("b failed"), "check B")
joined := errors.Join(a, b)
errors.Hints(joined) // [check A, check B]
errors.Is(joined, a) // true
errors.StackOf(joined) // a's stack
This is worth stating because it is not true of cockroachdb/errors, where
hints, details, context tags and telemetry keys all vanish below a Join — and
that includes joining a single error, since it wraps even one.
Nothing is copied upward to make this work. There is one chain traversal in the package and it descends into an aggregate, so every reader gets the same answer.
It has the standard-library shape¶
That holds here. It does not for cockroachdb, whose Join wraps the aggregate
in a stack wrapper — so the outermost value offers only a single Unwrap, and
anything walking single-unwraps treats the whole aggregate as a leaf.
Ordering¶
Members are visited in the order given, depth-first through nested aggregates. Hints and details de-duplicate; attributes do not, because an outer layer recording a key an inner one also recorded is information, and which wins is your decision rather than this package's.
Aggregating without discarding a diagnosis¶
A common shape is "try several sources, report only if none worked". Keep the failures and return them if nothing succeeds:
func first(sources []Source) (Result, error) {
var errs []error
for _, s := range sources {
result, err := s.Get()
if err != nil {
errs = append(errs, err)
continue
}
return result, nil // something worked: the failures were immaterial
}
return Result{}, errors.Join(errs...)
}
Because hints survive the join, a caller that gets nothing back still sees every suggestion the individual sources made.