errorlint は Go 1.13 で導入されたエラーラッピングの仕組みに沿わないコードを検出する静的解析ツールです。
解決する問題 Go 1.13 以降、errors.Is / errors.As / fmt.Errorf("%w", err) によるエラーチェーンが推奨されていますが、旧来の == 比較や型アサーションを使い続けるとラップされたエラーを見逃します。
1 2 3 4 5 6 7 8 9 10 11 12 if err == io.ErrUnexpectedEOF { } if e, ok := err.(*os.PathError); ok { } return fmt.Errorf("read config: %v" , err)
1 2 3 4 5 6 7 8 9 10 11 12 13 if errors.Is(err, io.ErrUnexpectedEOF) { } var pathErr *os.PathErrorif errors.As(err, &pathErr) { } return fmt.Errorf("read config: %w" , err)
設定 公式ドキュメント
1 2 3 4 5 6 7 8 9 10 11 12 version: "2" linters: enable: - errorlint settings: errorlint: errorf: true errorf-multi: true asserts: true comparison: true
オプション
オプション
型
デフォルト
説明
errorf
bool
true
fmt.Errorf で %w ではなく %v を使っている箇所を検出
errorf-multi
bool
true
%w を複数使用することを許可(Go 1.20 以降で有効。errorf: true が前提)
asserts
bool
true
err.(*Type) のような直接の型アサーションを検出
comparison
bool
true
err == ErrFoo のような直接のエラー比較を検出
allowed-errors
list
[]
直接比較を許可するエラーと関数の組み合わせを指定
allowed-errors-wildcard
list
[]
ワイルドカードで許可パターンを指定
allowed-errors の使い方 io.EOF のように意図的にラップしないことが保証されているエラーは、許可リストに追加して警告を抑制できます。
1 2 3 4 5 6 linters: settings: errorlint: allowed-errors: - err: "io.EOF" fun: "example.com/pkg.Read"
サンプル 検出例 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 func readFile (path string ) error { _, err := os.ReadFile(path) if err != nil { return fmt.Errorf("read file: %v" , err) } return nil } func processItem (ctx context.Context, id string ) error { item, err := fetchItem(ctx, id) if err == sql.ErrNoRows { return ErrItemNotFound } } func handleError (err error ) { if netErr, ok := err.(*net.OpError); ok { slog.Error("network error" , "op" , netErr.Op) } }
修正例 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 func readFile (path string ) error { _, err := os.ReadFile(path) if err != nil { return fmt.Errorf("read file: %w" , err) } return nil } func processItem (ctx context.Context, id string ) error { item, err := fetchItem(ctx, id) if errors.Is(err, sql.ErrNoRows) { return ErrItemNotFound } } func handleError (err error ) { var netErr *net.OpError if errors.As(err, &netErr) { slog.Error("network error" , "op" , netErr.Op) } }
注意点
io.EOF など標準ライブラリでラップしないことが保証されているエラーは自動的に除外される
--fix オプションで %v → %w、== → errors.Is、型アサーション → errors.As を自動修正できるが、switch 文は手動修正が必要
参考リンク