← All writing

TIL: errors.Join collects multiple errors in Go

1 min read gotil

Today I wanted to try a few fallbacks and, if they all failed, return one error that explains every attempt. Since Go 1.20 there’s a clean way to do that: errors.Join.

var errs []error
for _, cred := range candidates {
    if err := tryClone(repo, cred); err != nil {
        errs = append(errs, err)
        continue
    }
    return nil // one worked
}
return fmt.Errorf("all clone attempts failed: %w", errors.Join(errs...))

Two things I didn’t expect:

  • errors.Join(nil, nil) returns nil. Nils are skipped, so you can append freely without guarding.
  • errors.Is / errors.As see through it. The joined error wraps every child, so errors.Is(err, context.DeadlineExceeded) still matches even if the deadline error was just one of several.

The default Error() string prints each error on its own line, which is exactly what you want in a log. Small thing, but it replaced a pile of manual string-joining I’d been copy-pasting for years.