CLAUDE_CODE_STARTUP_FAILURE_RESULTSで起動失敗の理由を取得する
起動拒否の理由をstderrでなくresultメッセージで受け取る環境変数の仕様と、Agent SDKでの受け方をまとめます。
CLAUDE_CODE_STARTUP_FAILURE_RESULTSでできること
CLAUDE_CODE_STARTUP_FAILURE_RESULTS を 1 に設定すると、--output-format stream-json で起動したセッションが、起動に失敗した理由を result メッセージとして書き出すようになります。Claude Code v2.1.274以降の機能です。
これまで大半の起動失敗は、stderrへのエラー出力とゼロ以外の終了コードだけで終わっていました。stdoutをJSONとしてパースするAgent SDKのアプリケーションからは、失敗の種類を区別できず、リトライすべきか設定を直すべきかの判断がつきません。この環境変数を立てておくと、失敗の種類ごとに決まった文字列(SDKStartupFailureReason)がresultメッセージに載るため、アプリ側でエラーの種類に応じた案内を出し分けられます。SIGSEGVで起動直後に落ちるような致命的クラッシュとは別枠の、Claude Code自身が起動を拒否するケースが対象です。
何も設定しないとどうなるか
CLAUDE_CODE_STARTUP_FAILURE_RESULTS を設定しない状態でも、一部の起動失敗だけは元から result メッセージを書きます。公式ドキュメントが明記しているのは次の2つです。
- worktreeへ安全に戻れないと判断したresume。
worktree_unverifiedまたはworktree_resume_refusedが載ります - バックグラウンドセッションが保持している会話への
continueの拒否。session_held_by_backgroundが載ります(resumeの拒否では、この環境変数を設定したときだけ載ります)
それ以外の起動失敗は、環境変数を設定しない限りstderr出力とゼロ以外の終了コードのみで終わり、result メッセージは書かれません。worktree_unverified / worktree_resume_refused は、v2.1.260より前はresultメッセージ自体が存在しませんでした。
resultメッセージの中身
CLAUDE_CODE_STARTUP_FAILURE_RESULTS=1 で受け取る result メッセージは、subtype: "error_during_execution" として書かれ、次の特徴を持ちます。
startup_failure_reasonフィールドに、後述するSDKStartupFailureReasonのいずれかの値が入る- トークン数・コストなどの集計はゼロで埋まる
errors配列には、stderrに出るのと同じ文字列が入る- 他の
result(通常終了・APIエラーなど)にはこのフィールドは存在しない
startup_failure_reason を読み取るにはTypeScript Agent SDK v0.3.274以降が必要です。人向けの文言が欲しい場合はerrors配列をそのまま表示に使えます。そこにはstderrへ出るのと同じ文字列が入っているため、startup_failure_reasonで分岐しつつ、詳細メッセージはerrorsから引く、という組み合わせが実装として素直です。値ごとに独自の文言を作り込むか、errorsの文字列をそのまま出すかは、アプリケーションのUIがどこまで作り込まれているか次第です。
SDKStartupFailureReasonの値一覧
公式ドキュメントが定義する型は次の16種類です。
type SDKStartupFailureReason =
| "org_pin_api_key_conflict"
| "org_verify_failed"
| "org_pin_mismatch"
| "managed_settings_invalid"
| "remote_settings_required_unavailable"
| "gateway_signin_required"
| "gateway_access_denied"
| "proxy_invalid"
| "temp_dir_unusable"
| "cwd_unavailable"
| "shell_tool_missing"
| "session_held_by_background"
| "worktree_resume_refused"
| "worktree_unverified"
| "cli_version_too_old"
| "bypass_root";値ごとの意味は次のとおりです。組織のサインイン管理・ゲートウェイ関連が半分近くを占めます。
| 値 | 何が起きたか |
|---|---|
org_pin_api_key_conflict | 何が起きたか組織側がファーストパーティ / Cloudゲートウェイのサインインを必須にしているのに、APIキーやapiKeyHelperが設定されている |
org_verify_failed | 何が起きたかサインインの組織検証に失敗(ネットワーク障害やトークン失効など) |
org_pin_mismatch | 何が起きたかサインインしたアカウントが、許可された組織のpinと一致しない |
managed_settings_invalid | 何が起きたかmanaged設定が読めない、pinが組織を指定していない、またはモデル制限で選べるモデルが残っていない |
remote_settings_required_unavailable | 何が起きたか組織が必須にしているリモート設定を読み込めなかった |
gateway_signin_required | 何が起きたかCloudゲートウェイがこのサインインを終了させた |
gateway_access_denied | 何が起きたかmanaged設定の取得リクエストがゲートウェイから403で返された |
proxy_invalid | 何が起きたかproxy設定が完全なURLになっていない |
temp_dir_unusable | 何が起きたかユーザー用の一時ディレクトリが安全でない、または作成できない |
cwd_unavailable | 何が起きたか作業ディレクトリが削除・移動された、または読み取れない |
shell_tool_missing | 何が起きたかWindowsでシェルツールが見つからない(Git Bashがなく、PowerShellも無効 / CLAUDE_CODE_USE_POWERSHELL_TOOLで無効化) |
session_held_by_background | 何が起きたかresume / continue対象の会話がバックグラウンドセッションとして実行中 |
worktree_resume_refused | 何が起きたかセッションのworktreeが安全性チェックに失敗、またはworktree内部からresumeを起動した |
worktree_unverified | 何が起きたかworktreeを今回は検証できなかった(再試行で成功する可能性あり) |
cli_version_too_old | 何が起きたかこのClaude Codeのバージョンが、Anthropicが要求する最小バージョンを下回っている |
bypass_root | 何が起きたかrootユーザーとしてbypass permissionsモードを要求した |
リトライで直るものと、設定変更が要るもの
16種類の値は、そのままリトライしてよいものと、設定を直さない限り何度実行しても失敗し続けるものに分かれます。表の説明を読み替えると、次のように整理できます。
- 再試行で直る可能性がある:
worktree_unverified(検証が一時的に失敗しただけ)、org_verify_failed(ネットワーク障害が原因のことがある) - 原因によって対処が分かれる:
worktree_resume_refused。worktreeの内部からresumeを起動しただけの場合はworktreeの外(main checkout)から起動し直せば直ります。安全性チェックに失敗した場合の対処はrefusalの内容次第で、worktreeの作り直し・パスの変更・main checkout側のgitメタデータの修復のいずれかに分かれるため、表示されるメッセージの案内に従って判断する必要があります - 設定・環境そのものの修正が要る:
org_pin_api_key_conflict、org_pin_mismatch、managed_settings_invalid、remote_settings_required_unavailable、gateway_signin_required、gateway_access_denied、proxy_invalid、shell_tool_missing、cli_version_too_old、bypass_root - 実行環境の状態変化が原因:
temp_dir_unusable、cwd_unavailable、session_held_by_background
自動リトライを組むアプリケーションでは、この4分類のうち「設定・環境そのものの修正が要る」に該当する値が返ってきたら即座にリトライを止め、人が対応するまで待つ設計にしないと、同じ失敗を無駄に繰り返すことになります。
Agent SDKでの受け方
env オプションに他の環境変数と同じ形で渡します。次はタイムアウト系の変数と並べた例です(公式ドキュメントのタイムアウト設定例にCLAUDE_CODE_STARTUP_FAILURE_RESULTSを足した形)。
import { query } from "@anthropic-ai/claude-agent-sdk";
const result = query({
prompt: "Analyze this code",
options: {
env: {
...process.env,
CLAUDE_CODE_STARTUP_FAILURE_RESULTS: "1",
},
},
});
try {
for await (const message of result) {
if (
message.type === "result" &&
message.subtype === "error_during_execution" &&
message.startup_failure_reason
) {
// startup_failure_reason の値に応じて案内を出し分ける
console.error(message.startup_failure_reason, message.errors);
}
}
} catch (error) {
// query() はエラー結果を1件yieldしてから例外を投げるため、ここでも捕捉する
console.error(error);
}query() はエラー結果を1件yieldしてから例外を投げる実装なので、単発メッセージの呼び出しではループをtry節で囲んでおく必要があります。公式ドキュメントが明記しているのは、サンドボックスが起動できないときに同じ挙動(1件yieldしてから例外)になるという範囲までです。起動失敗のresultでも同じ動きになる前提で、念のためtryで囲んでおくと安全です。
シェルとsettingsファイル、どちらで設定するか
CLAUDE_CODE_STARTUP_FAILURE_RESULTSは、シェルのexportでも.claude/settings.jsonのenvブロックでも設定できます。両方に同じ変数があるときは、settingsファイル側の値が勝ちます。Claude Codeはenvエントリを実プロセスの環境変数として書き込み、シェルから継承した値を上書きするためです。
チーム全体で起動失敗を追跡したいなら.claude/settings.json(バージョン管理下)、自分の端末だけで検証したいなら.claude/settings.local.json(gitignore対象)に置くのが用途に合います。管理者が組織全体に強制したい場合はmanaged settingsに置くと、プロジェクト側の設定より優先されます。
CLIから直接呼び出す場合
Agent SDKを介さず、claude -pをそのまま呼ぶ運用でも同じ環境変数が効きます。次の例は起動失敗理由だけをjqで抜き出す形です。
CLAUDE_CODE_STARTUP_FAILURE_RESULTS=1 \
claude -p "run this task" --output-format stream-json --verbose | \
jq -r 'select(.type == "result" and .subtype == "error_during_execution") | .startup_failure_reason'--output-format stream-jsonはresultメッセージを含む複数行のJSONを標準出力に流すため、パイプで受けるシェルスクリプトや、他言語で自作したラッパーからも同じ形で読み取れます。CI上でclaude -pをラップしているだけの構成でも、Agent SDKを導入せずにこの環境変数だけ足せば起動失敗の分類ができます。
他のresult subtypeとの違い
resultメッセージのsubtypeにはerror_during_executionのほかに、error_max_turns(ターン数上限)、error_max_budget_usd(予算上限)、error_max_structured_output_retries(構造化出力の再試行上限)があります。startup_failure_reasonが載るのはerror_during_executionのときだけで、しかも起動そのものを拒否した場合に限られます。会話が始まってからターン数や予算の上限に達したケースでは、このフィールドは現れません。区別せずにerror_during_executionだけをフィルタすれば、起動失敗以外のサンドボックスエラー(有効化したサンドボックスが起動できない場合など)と混ざる点にも注意してください。こちらもstartup_failure_reasonを持たず、errors配列だけで理由を判別します。
セッションクラッシュのゼロ集計と混同しない
error_during_executionという同じsubtypeは、起動失敗以外にセッションクラッシュでも出ます。Claude Codeのプロセスが会話の途中で落ちたときも、最後にerror_during_executionのresultを書いて終了し、usage / total_cost_usd / modelUsageがゼロで埋まることがあります。
この2つは見分けが必要です。
- 起動失敗によるゼロ集計:
startup_failure_reasonが付き、会話は1ターンも始まっていない - セッションクラッシュによるゼロ集計:
startup_failure_reasonは付かず、それまでのターンのresultやassistantメッセージのusageから集計を復元できる
コストをtotal_cost_usdやresultの積算で追跡している実装では、error_during_executionを受け取ったら真っ先にstartup_failure_reasonの有無を見ることで、「そもそも課金が発生していない起動失敗」と「途中まで課金が発生したクラッシュ」を取り違えずに済みます。
Python Agent SDKでは使えるか
Python Agent SDKの公式リファレンスには、startup_failure_reasonやCLAUDE_CODE_STARTUP_FAILURE_RESULTSについての記載がありません。TypeScript Agent SDKのドキュメントだけがこのフィールドを定義しています。Pythonからclaude -p --output-format stream-jsonのサブプロセスを自前で起動している場合は、CLIの仕様として上記の環境変数とJSON構造がそのまま使えますが、Python SDK側の型定義としてのサポートは公式に明記されていません。
worktreeのresume拒否との関係
startup_failure_reason の説明で名指しされている代表例が、worktreeへのresumeが拒否されるケースです。セッションを終了した場所がworktree内部だった場合、Claude Codeは次回のresumeでそのworktreeへ戻ろうとしますが、git管理情報からworktreeの独立性を検証できないと再入場を拒否します。
--output-format stream-json を使っている場合、この拒否は元々v2.1.260以降であればresultメッセージ(subtype: error_during_execution)としてstdoutにも届いていました。CLAUDE_CODE_STARTUP_FAILURE_RESULTSが対象を広げるのは、それ以外の起動失敗(組織のサインイン検証・作業ディレクトリの消失など)にも同じ形でresultを出すようにする点です。非対話モード(-p)やAgent SDKのresumeでは、worktreeが消えているケース以外、この拒否によってセッションはisolationなしで続行せず停止します。
どのケースで設定すべきか
Agent SDKでClaude Codeを埋め込み、起動失敗を検知してユーザーに具体的な対処を案内したいアプリケーションでは有効です。典型的な使い分けは次のとおりです。
- CI・自動化パイプラインでresumeを多用する構成:
worktree_unverified(再試行で直る)とworktree_resume_refused(内部からの起動が原因なら外からの起動し直しで直り、安全性チェックの失敗ならrefusalの内容次第で作り直し・パス変更・main checkout側の修復に分かれる)を区別してリトライ戦略を分けられます - 組織のmanaged settingsでログインを制限している環境:
org_pin_api_key_conflictやorg_verify_failedを検知し、APIキー設定が残っている端末にサインイン手順を案内できます - 単発のCLI呼び出しをラップするだけの用途: 通常はstderrの文言をそのまま表示すれば足りるため、この環境変数を立てる必要性は薄くなります
CLAUDE_CODE_MAX_RETRIESやAPI_TIMEOUT_MSのような他のタイムアウト系環境変数と同様に、envオプションへまとめて渡せるので、起動失敗のハンドリングを追加するコストは小さめです。cwd_unavailableのように作業ディレクトリ絡みの失敗を見分けたい場合は、ClaudeCodeOptionsのcwdが反映されない問題もあわせて確認しておくと切り分けやすくなります。デバッグ出力を細かく見たい場合は--debugと--debug-fileでログ出力先を切り替える方法も役立ちます。