Goでの未処理エラーの修正:戻り値の無視を止める

beginner🔷 Go2026-05-12| golangci-lint、errcheck、reviveなどのリンターを使用しているGo (Golang) プロジェクト。

Error Message

unhandled error (Linter warning: Error return value of function Call() is not checked)
#go#エラーハンドリング#リンター#golangci-lint#errcheck

問題が発生する場所Goの設計では、エラーに正面から向き合うことが求められます。try/catchブロックに依存するJavaやPythonとは異なり、Goの関数は標準的な値としてerrorを返します。初心者はすべてが期待通りに動くと仮定して、これらのチェックをスキップしがちですが、この見落としこそがリンターの警告を引き起こす原因です。

標準のGoコンパイラは、戻り値を未使用の変数に代入しない限り、戻り値を無視してもブロックしません。しかし、golangci-lintのような静的解析ツールはこれを即座に検出します。CIパイプラインやIDEのターミナルでエラーが発生するのを目にすることになるでしょう。

// このコードは警告を発生させます
func saveConfig(data string) {
    os.WriteFile("config.yaml", []byte(data), 0644) // エラーが無視されています!
}

チェックを実行すると、おなじみのエラーメッセージが表示されます:

main.go:10:14: Error return value of function os.WriteFile is not checked (errcheck)

分析:サイレントな失敗のリスクエラーを無視することは危険な賭けです。もしディスクがいっぱいだったり、パーミッションエラーなどでos.WriteFileが失敗した場合、プログラムは10MBの設定ファイルが正常に保存されたかのように動作を続けます。これらの「サイレントな失敗」は、クラッシュが通常かなり後になってから、スタックの無関係な部分で発生するため、デバッグにおいて悪夢となります。

エラーが見落とされがちな、以下のハイリスクな関数に注意してください:

  • Close(): ファイル記述子やデータベース接続のクローズ。- Write(): HTTPレスポンスの送信やディスクへの書き込み。- json.Unmarshal(): バイト列から構造体への変換。- Exec(): データベースのマイグレーションや更新の実行。## クイックフィックス:ブランク識別子プロトタイプ作成中にリンターの警告を止めたいですか?その場合はブランク識別子 _ を使用します。これはGoに対して「失敗する可能性があることは分かっているが、今はあえて無視する」と伝えることになります。
func prototype(data string) {
    _ = os.WriteFile("test.txt", []byte(data), 0644)
}

プロのヒント: これは控えめに使用してください。リンターの警告を抑制しても、根本的なリスクは解決されません。単にツールから見えなくしているだけです。

恒久的な修正:プロフェッショナルなエラーパターン### 1. 標準的なガード節これはGoの基本中の基本です。エラーをすぐにチェックして処理しましょう。後回しにしてはいけません。

func saveConfig(data string) error {
    err := os.WriteFile("config.yaml", []byte(data), 0644)
    if err != nil {
        return fmt.Errorf("設定を保存できませんでした: %w", err)
    }
    return nil
}

2. Defer内でのエラーキャプチャファイルを閉じる処理は典型的な罠です。単純な defer f.Close() は、最終的なフラッシュ中の潜在的なエラーを無視します。関数がエラーを返す場合は、名前付き戻り変数を使用して、クリーンアップ中の失敗をキャプチャします。

func processFile(path string) (err error) {
    f, err := os.Open(path)
    if err != nil {
        return err
    }

    defer func() {
        closeErr := f.Close()
        // メインのエラーが現在nilの場合のみ上書きする
        if err == nil {
            err = closeErr
        }
    }()

    // ここにファイル処理のロジックを記述
    return nil
}

3. 「ログを記録して続行」アプローチバックグラウンドのゴルーチン内など、エラーを上位に伝播させることができない場合があります。そのような場合は、可視化が重要です。エラーをログに記録し、SentryやDatadogのダッシュボードで追跡できるようにします。

defer func() {
    if err := r.Body.Close(); err != nil {
        log.Printf("重要: ボディのクローズに失敗しました: %v", err)
    }
}()

4. 実際に無視しても安全な場合fmt.Printlnが返すエラーをチェックしている人はほとんどいません。標準出力への書き込みが失敗する場合、おそらく環境自体がすでにクラッシュしています。このような稀なケースでリンターを満足させるには、明示的に記述します。

_, _ = fmt.Fprintln(os.Stderr, "緊急ログエントリ")

検証:クリーンな状態の確認パターンを更新したら、業界標準のツールスイートを実行して修正を確認します。golangci-lintをまだ導入していない場合は、2分ほどでセットアップできるので、試す価値があります。

# 有効なすべてのリンターを実行
golangci-lint run ./...

未処理のエラーだけに焦点を当ててチェックするには、errcheckを使用します:

# まだインストールしていない場合はインストール
go install github.com/kisielk/errcheck@latest

# プロジェクトを監査
errcheck ./...

出力がゼロになることが目標です。それは、あなたのコードが堅牢であり、チームが本番環境で「幽霊バグ」を追いかける必要がないことを意味します。

Related Error Notes