Claude Code Desktopで400エラーが消えないときの対処法
Claude Code DesktopのCodeタブで400エラーが繰り返し発生する症状を、エラーリファレンスとGitHub issueの報告をもとに解説し、SessionEndフックでの緩和策を示します。
Claude Code Desktopで400エラーが繰り返し起きる症状
Claude Code DesktopのCodeタブで、いったん直したはずの400エラーが時間を置いて再発するという報告があります。GitHub issue #90002によると、症状はこの形で出ます。
API Error: 400 messages.940.content.0.text.start_timestamp: Extra inputs are not permitted
API Error: 400 messages.2.content.0.text.flags: Extra inputs are not permittedセッションを再インストールしても、別のClaudeアカウントに切り替えても再発します。会話履歴ファイル(JSONL)を手作業で修復しても、数時間後に同じセッションで再びエラーが出ることが報告されています。Desktopアプリが起動しない・403で止まるといった別の症状はClaude Code Desktopの起動トラブルで扱っており、今回の400エラーとは原因が異なります。
一部の環境では、応答の先頭に cached data for request <uuid> not found という文字列が紛れ込む症状も同時に観測されています。この文字列はモデルの出力ではなく、UI側が挿入したものとみられますが、400エラーと同じ書き込み処理が原因かどうかは報告者自身も確認できていません。
エラーリファレンスが説明する「Extra inputs are not permitted」の原因
Extra inputs are not permitted は、Claude Codeのエラーリファレンスに載っている既知のエラーです。ただしそこで説明されている原因は、今回のDesktop固有の症状とは別物です。
Claude CodeとAPIの間に挟まったプロキシやLLMゲートウェイが anthropic-beta リクエストヘッダーを取り除いてしまい、context_management や effort といったベータ機能用のフィールドをAPIが未知の入力として拒否するケースが説明されています。対処は、ゲートウェイ側で anthropic-beta ヘッダーを転送する設定にするか、CLAUDE_CODE_DISABLE_EXPERIMENTAL_BETAS=1 でベータ機能自体を無効にすることです。
GitHub issue #90002が報告しているのは、context_management や effort ではなく start_timestamp / stop_timestamp / flags という3つのキーです。フィールド名が違うため、ゲートウェイのヘッダー転送を直しても今回の症状は解決しません。「Extra inputs are not permitted」を含む400エラー全般のコード別対処はClaude APIのエラーハンドリング設計にまとめています。
GitHub issueが報告するDesktop Code tab特有の原因
issue #90002によると、アシスタントのテキストブロックに次のような形でキーが書き込まれます。
{
"start_timestamp": "2026-08-26T09:42:33.302643423Z",
"stop_timestamp": null,
"flags": null,
"type": "text",
"text": "…",
"citations": []
}start_timestamp / stop_timestamp / flags はAPIのメッセージスキーマに存在しないフィールドです。会話履歴からリクエストを組み立てる際にこの3つが混じっていると、APIは「余分な入力」として400を返します。報告者は、UI描画用に付与されたと見られる caller という別のキーは正しく除去されている一方で、この3つだけが除去されずにリクエストへ渡っていると指摘しています。
再現条件を最も単純化した報告(2026-08-27付のコメント)では、新規セッションの1通目は成功し、2通目で必ず400になるとされています。フックも長い履歴も関係なく、hello のような短い1通目を送った直後のアシスタント応答に、すでに3つのキーが付与されていたことも確認されています。
自分の環境で同じ状態になっているかは、直近のJSONLを直接見れば確認できます。Windowsなら %USERPROFILE%\.claude\projects 以下、macOS/Linuxなら ~/.claude/projects 以下に、プロジェクトごとのセッションファイルが並んでいます。
grep -l '"start_timestamp"\|"stop_timestamp"\|"flags"' ~/.claude/projects/**/*.jsonlヒットしたファイルがあれば、該当セッションは次のターンで400になる可能性があります。issue内の報告では、この3つのキーは user ロールのレコードには付かず、assistant ロールのテキストブロックにだけ現れるとされているため、grepの対象を絞り込みたい場合は "role":"assistant" を含む行に限定すると誤検出を減らせます。"flags" は一般的な語のため、無関係な設定値をキー名に使っている行も拾ってしまう点は事前に踏まえておくとよいでしょう。
再現条件と影響が及ぶ範囲
issue内のコメントが検証した範囲では、影響は利用形態によって分かれています。
| 利用形態 | 結果 |
|---|---|
| Desktop app、Codeタブ | 結果発生する |
| Claude Code CLI(ネイティブインストール) | 結果発生する |
| Desktop app、Coworkタブ | 結果発生しない |
| claude.ai(Web) | 結果発生しない |
モデルはSonnet・Opus・Fableのいずれでも再現し、プロジェクトフォルダやカスタムフックの有無も無関係と報告されています。再現を報告しているのはWindows環境が中心です。issueのコメントで分析に加わった人の多くは、自分自身は「Desktopを実行していない」「Windowsを実行していない」と断った上でログを読み解いており、macOS側で実際にどこまで再現するかはissueの情報からは確定できません。
SessionEndフックでtranscriptを洗浄する
issueの中では、セッション終了時に会話履歴JSONLから3つのキーを取り除く運用が、暫定の緩和策として繰り返し検証されています。同じ発想は、Claude CodeのSessionEndフックだけでも組めます。
SessionEndフックは、/clear やセッション終了時に呼ばれ、入力として現在のセッションの transcript_path(JSONLファイルのパス)を受け取ります。これを使い、セッションを閉じるタイミングで該当キーを削除するスクリプトを仕込みます。セッション内で400が起きた後にフォールバック応答を出す運用はStopFailureフックでAPIエラー終了時のフォールバックを書くが別に扱っており、SessionEndフックとは発火するタイミングが異なります。
{
"hooks": {
"SessionEnd": [
{
"hooks": [
{
"type": "command",
"command": "${CLAUDE_PROJECT_DIR}/.claude/hooks/sanitize-transcript.sh"
}
]
}
]
}
}#!/bin/bash
# .claude/hooks/sanitize-transcript.sh
INPUT=$(cat)
TRANSCRIPT=$(echo "$INPUT" | jq -r '.transcript_path')
[ -f "$TRANSCRIPT" ] || exit 0
jq -c '
if (.message.content | type) == "array" then
.message.content |= map(if type == "object" then del(.start_timestamp, .stop_timestamp, .flags) else . end)
else
.
end
' "$TRANSCRIPT" > "${TRANSCRIPT}.tmp" && mv "${TRANSCRIPT}.tmp" "$TRANSCRIPT"JSONLの各レコードは message.content がオブジェクトの配列(アシスタントのテキストブロックなど)のときと、単なる文字列(ユーザーが送った短いプロンプトなど)のときが混在します。文字列のレコードに map をそのまま適用すると jq が「文字列は配列ではない」というエラーで終了し、後続の mv が実行されずスクリプト全体が無効になるため、type で配列かどうかを先に判定しています。
注意点が2つあります。1つ目は、SessionEndフックの既定のタイムアウトが1.5秒しかないことです。issueで扱われているような数MB規模のJSONLをjqで書き換えるには足りない場合があります。CLIから起動する場合は CLAUDE_CODE_SESSIONEND_HOOKS_TIMEOUT_MS 環境変数で全体の予算を引き上げられますが、DesktopアプリのCodeタブはこの起動方法を取らないため環境変数を渡せません。Desktopでも効くのは、フックの設定自体に timeout フィールドを追加する方法です。この値を設定すると、SessionEnd全体の予算もその値まで自動的に引き上がります(最大60秒)。
{
"hooks": {
"SessionEnd": [
{
"hooks": [
{
"type": "command",
"command": "${CLAUDE_PROJECT_DIR}/.claude/hooks/sanitize-transcript.sh",
"timeout": 10
}
]
}
]
}
}CLIから起動する場合に限っては、次のように環境変数で上書きすることもできます。
CLAUDE_CODE_SESSIONEND_HOOKS_TIMEOUT_MS=5000 claude2つ目は、SessionEndフックにはセッション終了を止める権限がないことです。あくまで後始末用のフックなので、「次に開いたときのJSONLがきれいな状態から始まる」ことしか保証できません。issue内では、実物の9.4MBのJSONLに合成の start_timestamp キーを注入し、SessionEndフックで除去してから再度開くと、そのセッションが問題なく動いたという検証結果が報告されており、後始末としての有効性自体は確認されています。
なお、リクエストをネットワーク越しに整形するプロキシ方式は、issue内の検証で ANTHROPIC_BASE_URL の上書きがDesktop Code tabに反映されないと報告されており、GUIから組み込むのは難しいとされています。SessionEndフックはDesktop環境でも .claude/settings.json から設定できるため、GUI側の制約を受けにくい手段です。
手動でJSONLを直しても再発する理由
issue #90002の報告者は、818個のJSONLファイルを一括で洗浄して、キーの出現がゼロであることを確認した当日のうちに、同じ3つのキーが別のファイルに再び現れたと記録しています。セッション終了時の洗浄だけでは足りず、新規セッションの2通目でも同じ400が出た、という報告もあります。
これはコメント欄でも整理されている通り、「保存先(JSONLファイル)を掃除すること」と「書き込んでいる処理そのものを止めること」が別の問題だからです。SessionEndフックが直せるのは前者だけで、セッションの最中に同じキーが再び書き込まれるのを防ぐものではありません。手動での書き換えやSessionEndフックによる洗浄は、次にセッションを開いたときの初期状態をきれいにする効果はあっても、進行中のセッションを400から守る手当てにはなりません。
エラーメッセージが tool_use concurrency issues や thinking blocks ... cannot be modified の場合は、フィールド名が異なる別の不整合です。この系統はエラーリファレンスで /rewind での復帰が案内されており、対処はtool_resultとtool_useの400エラーで扱っています。
start_timestampのバグは直ったのか、確認されていないだけなのか
issue #90002はクローズされておらず、オープンな状態が続いています。一方で、2026-09-04付けのコメントでは、その日の朝のアップデート後にエンジン2.1.258以降で再現しなくなったと報告されています。報告者は ANTHROPIC_BASE_URL の上書きとプロキシによる緩和策を完全に外した上で、当日書き込まれたJSONLに3つのキーが一件も現れていないことと、セッション終盤の会話文に不審な接頭辞が付かなくなったことの両方を確認しています。
| 時期 | エンジンバージョン | 状況 |
|---|---|---|
| 2026-08-26〜27 | エンジンバージョン2.1.246 | 状況問題が最初に報告される |
| 2026-08-31 | エンジンバージョン2.1.247 | 状況コミュニティ製プロキシ型緩和策が個別環境で検証される |
| 2026-09-01 | エンジンバージョン2.1.257 / 2.1.258 | 状況この前後のアップデートを境に「再現しなくなった」との報告が上がる |
| 2026-09-04 | エンジンバージョン2.1.258 | 状況該当環境でJSONLへの書き込み自体が止まったことを確認 |
| 2026-09-25 | エンジンバージョン2.1.283 | 状況changelogに本件を名指しした修正の記載はなく、issueはクローズされていない |
同じissue内のコメントは、2.1.246から2.1.260までのchangelogを検索しても start_timestamp や stop_timestamp や flags を名指しした行が見つからないと指摘しています。つまり「あるアップデートを境に再現しなくなった」という個別の観測と、「Anthropicがこの不具合の修正をchangelogで認めた」という事実は、今のところ別の話です。手元の環境で再現するかどうかを確かめる最も確実な方法は、claude --version でエンジンのバージョンを確認した上で、実際に新規セッションを2通やり取りしてみることです。
claude --versionまとめ
Claude Code Desktopで繰り返す400エラーのうち、エラーリファレンスが説明しているのは anthropic-beta ヘッダーが失われるゲートウェイ起因のケースだけです。start_timestamp / stop_timestamp / flags という別のキーが会話履歴に書き込まれて起きる400は、GitHub issue #90002でコミュニティが調査を続けている段階で、Anthropicによる名指しの修正はまだ確認されていません。手元で再発する場合は、まず claude --version で使っているエンジンのバージョンを確認し、SessionEndフックでセッションを閉じるたびにJSONLを洗浄する運用を挟みつつ、issue #90002の更新を追うのが現実的な対応です。