mcpField
M
m06-error-handling

m06-error-handling

github.com/actionbook開発1.6k3.5k 回インストール9 週間前に更新
リポジトリ

m06-error-handling について

Rust 開発者向けに、ライブラリやアプリのエラー処理を設計するスキルです。想定内の失敗とバグを区別し、適切な型や伝播方法、コンテキストを選ぶ手助けをします。

主な機能

  1. 01想定内の失敗とバグの分類
  2. 02Result、Option、panic の選択
  3. 03ライブラリとアプリのエラー処理比較
  4. 04エラー伝播時のコンテキスト保持

活用シーン

  1. 01API のエラー戻り値の設計
  2. 02危険な unwrap の置き換え
  3. 03伝播するエラーへの情報追加

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/actionbook/rust-skills --skill m06-error-handling

インストール後、Claude Code で/m06-error-handlingを入力して読み込まれたか確認します。

同梱ファイルexamples/library-vs-app.mdpatterns/error-patterns.md

詳細

エラー処理

レイヤー 1:言語の仕組み

中心となる問い

この失敗は想定内ですか、それともバグですか?

エラー処理の戦略を選ぶ前に:

  • 通常の動作中に失敗する可能性はありますか?
  • この失敗は誰が処理すべきですか?
  • 呼び出し元にはどのようなコンテキストが必要ですか?

エラー → 設計上の問い

パターンただ「こうする」と言うのではなく代わりに問いかけること
unwrap によるパニック「? を使う」ここで None/Err が実際に起こり得ますか?
? の型の不一致「anyhow を使う」エラー型は適切に設計されていますか?
エラーコンテキストの喪失「.context() を追加する」呼び出し元は何を知る必要がありますか?
エラーの種類が多すぎる「Box を使う」エラーの粒度は適切ですか?

思考のヒント

エラーを処理する前に:

  1. これはどのような種類の失敗ですか?

    • 想定内 → Result<T, E>
    • 不在が通常の状態 → Option
    • バグ/不変条件 → panic!
    • 回復不能 → panic!
  2. 誰が処理しますか?

    • 呼び出し元 → ? で伝播する
    • 現在の関数 → match/if-let
    • ユーザー → わかりやすいエラーメッセージ
    • プログラマー → メッセージ付きでパニックする
  3. どのようなコンテキストが必要ですか?

    • エラーの種類 → thiserror のバリアント
    • 呼び出しチェーン → anyhow::Context
    • デバッグ情報 → anyhow または tracing

上位をたどる ↑

エラー戦略が明確でない場合:

"Should I return Result or Option?"
    ↑ Ask: Is absence/failure normal or exceptional?
    ↑ Check: m09-domain (what does domain say?)
    ↑ Check: domain-* (error handling requirements)
状況たどる先問い
unwrap が多すぎるm09-domainデータモデルは適切ですか?
エラーコンテキストの設計m13-domain-errorどのような復旧が必要ですか?
ライブラリとアプリのエラーm11-ecosystem利用者は誰ですか?

下位をたどる ↓

設計から実装へ:

"Expected failure, library code"
    ↓ Use: thiserror for typed errors

"Expected failure, application code"
    ↓ Use: anyhow for ergonomic errors

"Absence is normal (find, get, lookup)"
    ↓ Use: Option<T>

"Bug or invariant violation"
    ↓ Use: panic!, assert!, unreachable!

"Need to propagate with context"
    ↓ Use: .context("what was happening")

クイックリファレンス

パターン使用する場面例
Result<T, E>回復可能なエラーfn read() -> Result<String, io::Error>
Option<T>不在が通常の状態fn find() -> Option<&Item>
?エラーを伝播するlet data = file.read()?;
unwrap()開発/テスト時のみconfig.get("key").unwrap()
expect()不変条件が成立する場合env.get("HOME").expect("HOME set")
panic!回復不能panic!("critical failure")

ライブラリとアプリケーション

コンテキストエラークレート理由
ライブラリthiserror利用者向けの型付きエラー
アプリケーションanyhow人間工学的なエラー処理
混在両方境界では thiserror、内部では anyhow

判断フローチャート

Is failure expected?
├─ Yes → Is absence the only "failure"?
│        ├─ Yes → Option<T>
│        └─ No → Result<T, E>
│                 ├─ Library → thiserror
│                 └─ Application → anyhow
└─ No → Is it a bug?
        ├─ Yes → panic!, assert!
        └─ No → Consider if really unrecoverable

Use ? → Need context?
├─ Yes → .context("message")
└─ No → Plain ?

よくあるエラー

エラー原因修正方法
unwrap() によるパニックNone/Err が未処理? または match を使う
型の不一致エラー型が異なるanyhow または From を使う
コンテキストの喪失コンテキストなしの ?.context() を追加する
cannot use ?Result の戻り値がないResult<(), E> を返す

アンチパターン

アンチパターン問題点より良い方法
あらゆる場所で .unwrap() を使う本番環境でパニックする.expect("reason") または ?
エラーを黙って無視するバグが隠れる処理するか、伝播させる
想定内のエラーに panic! を使うUX が悪く、復旧できないResult
あらゆる場所で Box を使う型情報が失われるthiserror

関連スキル

場面参照先
ドメインエラー戦略m13-domain-error
クレート境界m11-ecosystem
型安全なエラーm05-type-driven
メンタルモデルm14-mental-model

コメント