テック技報最新号へ →
コード

Go: 独立した複数のエラーは errors.Join でまとめて返す

Go 1.20 以降の errors.Join(err1, err2, ...) は複数のエラーを 1 つにまとめる。Close とフラッシュの両方が失敗したときなどに、片方を握りつぶさずに返せる。

@amitsinha__07 · 投稿 2026-11-07
#go#error-handling

使う場面

  • defer f.Close() のエラーと本処理のエラーを両方返したいとき
  • 複数のバリデーションエラーや、複数の後始末の失敗をまとめて報告したいとき
  • 以前は「最初のエラーだけ返す」か自前の multierror 型を使っていた場面

やり方

go
func writeFile(path string, data []byte) (err error) {
    f, err := os.Create(path)
    if err != nil {
        return err
    }
    defer func() {
        err = errors.Join(err, f.Close()) // nil は無視される
    }()
    _, err = f.Write(data)
    return err
}

// 呼び出し側は従来どおり判定できる
if errors.Is(err, fs.ErrPermission) { ... }
var pe *fs.PathError
if errors.As(err, &pe) { ... }
  • 引数の nil は捨てられ、全部 nil なら errors.Join も nil を返す。だから errors.Join(err, f.Close()) をそのまま書ける。
  • errors.Is / errors.As は、まとめた中のどれかに一致すれば true になる。
  • Error() の文字列は各エラーを改行でつないだもの。

注意点

  • ログで 1 行にしたい場合、改行が入る点に注意(構造化ログなら問題になりにくい)。
  • 「A が失敗したので B を実行しなかった」のような因果関係があるなら、Join ではなく fmt.Errorf("...: %w", err) でラップするほうが意味が伝わる。Join は互いに独立した失敗向け。
  • fmt.Errorf でも %w を複数書けば同様に複数ラップできる(Go 1.20+)。

出典

X の元の投稿を開く