Claude Codeで出てくる「court」って何? “XML露出” 現象とツール呼び出し未実行事故の対策
こんにちは!
Qualitegプロダクト開発部です。
Claude Code を使っていると、ツール呼び出しの XML(<invoke> や <parameter>)が画面にそのまま表示されたり、実際にはコマンドや PR 作成が実行されていないのに「完了しました」と報告されたりして、動作がおかしくなることがあります。
そして、その呼び水となる文字列 court が出現します
本稿では、
この現象(本稿では「XML露出」と呼びます)を実ログから解説し、検知と対策をまとめました。
court や生の <invoke> が画面に出ている方へClaude Code を使っていると、まれに <invoke> や <parameter> といったXML風の文字列が、そのまま会話画面に表示されることがあります。
見た目が崩れるだけなら、単なる表示上の不具合に思えるかもしれませんが、 その文字列が示していたはずの
ツール操作が、実際には実行されていない ことがあるこ
とです。
ファイル編集、シェルコマンド、サブエージェント起動、PR作成などが行われていないにもかかわらず、後続の応答が「完了した」前提で進むこともあります。
本稿では、この現象を便宜上「XML露出」と呼びます。 (公式な障害名ではありません)
実際のセッションログをもとに、何が観測できたのか、どこから先が推定なのか、そして運用では何を確認すべきなのかを整理していきたいとおもいます。
なお、よく似た現象は、Anthropic の Claude Code 公式リポジトリにも、利用者による不具合報告として複数投稿されています。
生の <invoke> がテキストとして表示される、stop_reason="tool_use" なのに対応する tool_use が記録に無い、その結果としてコミットやPRが作られていなかった、
といった内容です。
複数の類似報告があり、個別環境だけの偶発的な表示崩れではなさそうです。
本稿公開時点(2026年6月)では、この現象を修正したと明記する公式changelogエントリは確認できず、関連Issueの多く(#63870/#64108/#64690/#68354 ほか)はオープンまたは重複クローズの状態です。
本ブログで紹介する対処方法はすべて、公式修正を待つ間のワークアラウンドとお考えください
1. この現象を本稿で「XML露出」と呼びます
「XML露出」とは、ツール呼び出し用とみられるXML風マークアップ(<invoke> や <parameter> など)が本文に露出し、対応する操作が実行されない、または正常に実行されたか確認できなくなる現象を指す、本稿内の便宜的な呼称です。公式名称ではありません。
露出したからといって常に未実行とは限らず、確実に言えるのは「正常なツール呼び出しとして処理されたかを判断できない」ことです
(後述の復旧手順は、この前提に立っています)。
要点は、二つの問題が重なった状態として捉えることです。
(1)ツール呼び出しパイプラインの不整合 … モデルの出力が、記録上、構造化された tool_use ブロックとして確認できず、対応する実行結果も確認できない。
(2)呼び出しと完了の混同 … 操作が実行された前提で、後続のモデル出力が「完了しました」という文章を生成してしまう。
(1) は、ユーザー側の運用だけで完全に防ぐことは困難です。
だからこそ (2) を断つこと 、 出力(宣言)を信じず、実行結果で確かめる、 が対策の核心になります。 そして「XML露出」は、見た目にすぐ分かるため、ツール呼び出しパイプライン異常の早期警報(カナリア)として使えます。
2. 正常なツール呼び出しはどう動くか
まず、正常時の仕組みを押さえておきましょう。
Claude API の公開仕様では、クライアントツール(Bash やファイル編集など、利用側で実行するツール)の場合、モデルがツールを使いたいとき、応答は stop_reason: "tool_use" と、1個以上の tool_use コンテンツブロックとして返されます。
クライアント側(実行基盤)はそのブロックを読み、実際のツールを実行し、結果を tool_result ブロックとして返します。
モデルはその結果を受け取って続きを生成します。
(Web 検索などのサーバーツールは Anthropic 側で実行されるため、この限りではありません。本稿が扱うのはクライアントツールです。)
「ツールの要求」「ツールの実行」「実行結果の確認」が別々の段階でおこる、ということが重要ですね。
stop_reason: "tool_use" は、あくまでモデルが実行を要求していることを示すメタデータであり、ツールが実行された証拠ではありません
(詳細は How tool use worksがくわしいです)。
一方、<function_calls> や <invoke> といったXML風の表記は、Claude API の公開仕様として保証された形式ではありません。
これは Claude Code 系の内部表現、あるいは失敗時のシリアライズ表現とみられるもので 本稿の対象も「LLMエージェント一般」ではなく、Claude Code および Claude 系エージェントで観測された現象に限定します。
(公開API上の正常な流れ)
モデル: stop_reason="tool_use" + tool_use ブロック ← 実行の「要求」
↓
クライアント: tool_use を読み、実際に実行
↓
クライアント: tool_result を返す ← 実行の「結果」
↓
モデル: 結果を受けて続きを生成
ということで、「XML露出」は、この流れのどこかで、ツール呼び出しが記録上、構造化された tool_use ブロックとして確認できず、対応する実行結果も確認できない状態に相当します。
3. 実ログで起きていたこと
発生環境(実測値) はこんなかんじですます。
| 項目 | 値 |
|---|---|
| Claude Code バージョン | 2.1.179 (Claude Code) |
| 使用モデル | claude-opus-4-8[1m] |
| 拡張(1M)コンテキスト | 有効(モデルID末尾 [1m]、/context が「… / 1m tokens」表記) |
| OS・端末 | Windows 11系(10.0.26200.8246)、シェルは Git Bash/MSYS(MINGW64_NT-10.0-26200) |
| 環境変数 | CLAUDE_AUTOCOMPACT_PCT_OVERRIDE 未設定/ANTHROPIC_MODEL 未設定(いずれも既定動作) |
発生前後の /context 実測 |
約55%(549.7k / 1M tokens) |
※ これらは「同じ環境なら必ず再発する」ということはなく、単に観測時の条件となります。
とりわけ、Opus 4.8 の 1M コンテキストを有効化し、文脈使用率が半分程度(約55%)に達した状態で発生した点は、後述の context rot に関する仮説(§5)と照らして記録しておく価値があります。
舞台は、サブエージェントを4体ずつ「波(wave)」で並列起動し、多数のタスクを順に処理していたセッションです。波1〜波6までは正常でした。問題は波7で起きました。
3-1. XMLが本文に露出したログ
まず、利用者の画面には次のような見え方になります。本来は裏で実行されるはずのツール呼び出しが、ただの文字列としてそのまま表示されます
(この時点で、これらの操作は正常に実行されたかどうか、わからず)
波6完了。波7(タスク0001-0004)を起動します。
court
<invoke name="Task">
<parameter name="description">作業 0001</parameter>
<parameter name="subagent_type">general-purpose</parameter>
<parameter name="prompt">あなたはタスク実行エージェント。対象: task-0001。…(長文プロンプト)…</parameter>
</invoke>
<invoke name="Task"> …0002… </invoke>
<invoke name="Task"> …0003… </invoke>
<invoke name="Task"> …0004… </invoke>
これを記録(トランスクリプト)として見ると、次のようになっていました。
{
"role": "assistant",
"content": [
{
"type": "text",
"text": "波6完了。波7(タスク0001-0004)を起動します。\n\ncourt\n<invoke name=\"Task\">\n<parameter name=\"description\">作業 0001</parameter>\n<parameter name=\"subagent_type\">general-purpose</parameter>\n<parameter name=\"prompt\">あなたはタスク実行エージェント。対象: task-0001。…(長文プロンプト)…</parameter>\n</invoke>\n<invoke name=\"Task\"> …0002… </invoke>\n<invoke name=\"Task\"> …0003… </invoke>\n<invoke name=\"Task\"> …0004… </invoke>"
}
],
"stop_reason": "tool_use",
"usage": { "output_tokens": 3809 }
}
このログから読み取れるのは、、
content の型が "text" = <invoke …> の塊は、構造化された tool_use ブロックとしてではなく、ただの本文テキストとして記録されています。 にもかかわらず stop_reason は "tool_use" = 応答上は「ツール実行を要求して停止した」状態です。
崩れの痕跡として、XML風の断片がいきなり <invoke> から始まっており、その直前には court という宙ぶらりんの語も見えます。
<invoke name="Task"> が4連発 = 長文プロンプトのサブエージェントを4体まとめて並列起動しようとしていたことがうかがえます。
※ 先頭に紛れる court(環境によっては call)という素のテキストは、本稿だけの偶発ではなく、公式リポジトリの不具合報告でも、ツール呼び出しが実行されず生の <invoke> が露出する直前のサインとして繰り返し観測されているみたいです(Issue #64108/#68354)。
冒頭のデモは、同じ現象を Bash 呼び出しで示した例ですが、露出するツールは Task に限らず Bash/Edit/Read など複数種類で報告されており、本稿の波7の例(Task の並列起動)も、その一形態とのようです
3-2. ツール呼び出しが記録に残らなかったログ
その直後(出し直した)ターンです。
{
"role": "assistant",
"content": [
{ "type": "text", "text": "サブエージェント波7(タスク0001-0004)を起動します。" }
],
"stop_reason": "tool_use",
"usage": { "output_tokens": 3609 }
}
content は前置きの一文だけで、<invoke> のかけらもありません。
なのに stop_reason は "tool_use"、output_tokens は 3609 です。 stop_reason と content の食い違い(「ツール実行を要求して止まった」とされているのに、記録上は実行可能な tool_use ブロックが1つも無い)が、この現象の核心にみえます。
これは「モデルが地の文にうっかり書いた」だけでは説明できず、XMLが見えた前者は「部分的に露出した」現れ方、見えなかった後者は「記録に残らなかった」現れ方であり、同じ不整合の二つの現れ方とも考えられます。
なお、output_tokens には表示された本文だけでなく、thinking(拡張思考)等のトークンが含まれる場合があるので、3609 という数字だけを根拠に「数千トークン分のツール呼び出しが消えた」と安易に結論づけることもできないでしょう。
で、何が重要かというと、トークン数ではなく、stop_reason="tool_use" と、記録されたコンテンツブロックとの不整合の部分ではないでしょうか。
4. ログから分かること/分からないこと
ここで、ログで断定できることと、できないことを切り分けておきましょう。
うっかり原因を決め打ちしたくないので、整理します。
| 区分 | 内容 |
|---|---|
| 観測事実 | XML風タグが text として記録された/stop_reason="tool_use" なのに実行可能な tool_use ブロックが無い/対応する実行結果が確認できない |
| 仕様上の事実 | stop_reason="tool_use" は実行の「要求」であって「結果」ではない/実行とその確認は別段階 |
| 推定 | モデル生成・ストリーミング変換・SDK/CLIのパース・トランスクリプト保存のいずれかの段階で不整合が生じた(どこかは特定できない) |
| 運用仮説 | 長文・並列・複雑な引数が発生率を上げる可能性がある(観測ベースの仮説) |
つまり、このログから確実に言えるのは、
記録された応答内に構造化された tool_use ブロックがなく、対応する tool_result も確認できないことまでです。
モデルが正しい呼び出しを生成しなかったのか、ストリーミングやパースで失われたのか、トランスクリプトへの保存時に欠落したのかは、このログだけでは特定できません。
したがって本稿では、「ハーネス側の捕捉漏れ」と原因を確定はせず、
「ツール呼び出しパイプラインの不整合が確認できる」
という表現にとどめました。
5. なぜ運用上危険なのか
さて、危険の本質は、見た目の乱れではなく進行の食い違いにあります。
実行記録から見ると
stop_reason="tool_use" だが、対応する構造化 tool_use や tool_result が無い
→ その操作が正常に実行されたことを確認できません。
後続のモデル出力から見ると
操作が完了した前提で文章が続く
→ 結果が返った前提で次に進みます。
なお今回の事例では、後続の状態および成果物を照合した結果、対象タスクが未実行だったと判断しています
(一般論としての「確認できない」と、今回の実測としての「未実行だった」は分けて扱います)。
このズレが2つの事故を生みます。
(1) 実行結果を伴わない成功報告
副作用のある操作で特に問題になります。
gh pr create の呼び出しが生成される。
しかし実行可能な tool_use として渡らず、実行されない。
それでも後続の応答は「PRを作成しました」と述べ、PRをつくった気になってい、それらしいURLを提示する。
でも、 ユーザーがクリックすると 404。
PRなんぞ存在しないではないか。
「動いた/できた」を実行結果ではなく文章として報告してしまうのが、最大の害です。
(2) サイレント欠落(処理した前提の未処理)
バッチ処理では、
「波7を起動した前提で実際は1体も動かず、そのまま波8へ進む」
という静かな取りこぼしが起き得ます。
「波7 完了」と表示
→ 実際は タスク0001〜0004 が未処理
→ 後工程は「全部やった」前提で進む
→ 最終成果から4件が静かに欠落。
§3のログでは結果的に救われています
(直後に波7を再送し、対象タスクがその後の数ターンに連続して現れた=リカバリ成功)。
ですが、気づかなければ欠落は静かに残りますし、stop_reason だけ見ると成功に見えるため、自動進行・無人運転ほど危険です。
なぜ長文・並列セッションで起きやすいと考えられるか
長い文脈で指示追従や想起の精度が落ちる「context rot」自体は、
Anthropic の公式資料でも、トークン数の増加に伴って精度や想起能力が低下する現象として説明されています
(Effective context engineering for AI agents)。
長時間・ツール多用セッションで「XML露出」が発生したという報告は複数あり、長文脈下では指示追従や構造保持が不安定になりやすい、という仮説と整合的です。
ただし、セッション開始直後から発生したという報告もあり、並列ツール呼び出しやツール構成との関連を疑う報告もあります。
したがって、 「XML露出」はセッション品質劣化の早期警報として利用できます。
ただし、短いセッションでの報告もあり、context rot だけを原因とみなすことはできません。 という整理が妥当です。「XML露出」は context rot のカナリアというより、ツール呼び出しパイプライン異常のカナリアと捉えるほうが正確です。
6. 検知・復旧・予防
6-1. 検知(diagnostics)
まず検知です。
露出して「見える」ものは気づけます。怖いのは記録に残らない形と、実行結果を伴わない成功報告なので、見た目に頼らず機械的・実測的に検知します。完了は宣言ではなく結果で判定するのが原則です。
| 検知シグナル | 見るもの | 異常/合格の条件 |
|---|---|---|
| stop_reason と tool_use の突き合わせ | 応答の stop_reason と実行可能な tool_use 件数 |
stop_reason=="tool_use" なのに tool_use が0個 → 異常 |
| 先頭の素テキスト検出 | ツール呼び出し直前の単独行 | call / court が出たら露出の前触れとしてフラグ |
| 宣言と実行件数の一致 | 「N件起動」宣言 vs 実 tool_use/結果件数 |
件数が N と不一致 → 異常 |
| 本文への生タグ出現 | 応答本文のテキスト | <invoke / <function_calls / <parameter が出たら即フラグ |
| 完了は結果で判定 | tool_result の有無と内容 | ①要求 → ②tool_result 返却 → ③成功表示 → ④期待した外部状態、まで揃って完了 |
| 副作用操作のリモート裏取り | push/PR/マージ/反映物の実体 | SHA一致/gh pr view の state/git ls-tree でファイル実在を確認。URLは貼る前に実在確認 |
| 処理対象の母数照合 | 対象集合 vs 成果が生成された集合 | 「全件処理」工程の後で差集合がゼロか機械突合 |
| 併発兆候の監視 | 説明の反復/決定の聞き直し/宣言だけで未実行 | 同セッションの品質低下サイン。確認強化・セッション区切りの判断材料に |
6-2. 復旧(出てしまったら)
操作によっては危険なので慎重に進めます。
・PR / push →
gh pr view <番号> --json url,state/git ls-remote origin <branch>・ファイル編集 → 対象ファイルを開いて、変更が入っているか目視
2回続けて崩れたら: そのセッションは捨て、状態をメモして新セッション(
/clear)へ。
さて、上記コラムのとおり、
露出した呼び出し自体は通常は未実行ですが、
・同じターンの別ツールが先に実行されていたり、
・並列バッチの一部だけ走っていたりすることがあります
(並列呼び出しでは1件の失敗が兄弟呼び出しのキャンセルを招くという報告もあります)。
PR作成・デプロイ・課金・メール送信などを無条件に再実行すると二重実行の恐れがあるため、まず外部状態を確認してから慎重に動きましょう。
| # | 手順 | ポイント |
|---|---|---|
| 1 | 露出した呼び出しを実行済みと数えない | XMLとして見えたものは「未実行の可能性が高い」前提で扱う |
| 2 | 現在の外部状態を確認する | 同じターンの他操作も含め、部分実行の有無をチェック |
| 3 | 未実行を確認してから再試行する | 操作は1件に絞る。長い引数・複数ツールの並列は分割。可能なら冪等な形に |
| 4 | 副作用操作は裏取りしてから再実行 | 一意なID/外部状態を確認してから再試行し、二重実行を防ぐ |
| 5 | 崩れが続くならセッションを終了する | 崩れた状態に積み増さない。状態を引き継ぎ文書に外部化し、新セッションでやり直す |
ざっくりいうと、露出したXMLが示すコマンドは本当に実行されてるのか(実行されてない可能性高い)を確認して、引継ぎ文章をつくらせて、はやめにそのセッションを終わらせる という感じが良さそうです。
ただ、症状がおもいと引継ぎ文章すらつくれないので、そういう場合は、
①XML露出が怒ってしまったセッションログをコピペして、
②「こういう事象で前セッションを途中終了したけど、続きをやってほしい」
と新セッション側で伝えることも効果的です。
6-3. 予防(出る前に)
発生率を上げると疑われるのは、長文・並列・複雑な引数です。要求を小さく分け、品質が落ちる前に区切る・圧縮する・状態を外に出す、が予防の柱です。
| 予防策 | 狙い・やり方 |
|---|---|
| 多並列・長パラメータを一度に投げない | 長文プロンプトのサブエージェントは同時数を絞る(経験則で3〜4体まで) |
| 巨大コマンドにまとめない | 長い正規表現・heredoc・Windowsパス等はスクリプトファイルに分離し、エスケープ密度を下げる |
| 説明と実行を同じ要求に詰めない | 長文の説明と多数の操作を一括で投げず、分けて出す |
| 一度に要求する操作を絞る | 重要な副作用操作(PR作成・デプロイ等)は1件ずつ実行・確認する |
| 1セッション = 1テーマで早めに区切る | 区切ったら成果を commit して会話をクリアするか、新セッションへ |
| 品質が落ちる「前」に手動で圧縮(/compact) | 落ちてから圧縮すると、混乱ごと要約に入り悪化することがある |
| 状態を常に外部化する | 「引き継ぎ文書+次回の作業指示書」を都度書く習慣が context rot への王道 |
6-4. 仕組みで守る(設計・運用)
個々の注意ではなく、運転ループ自体に「宣言と結果を突合する関門」を組み込みます。stop_reason を完了の証拠にしないのが前提です。
| 設計原則 | 具体策 |
|---|---|
| 「起動宣言」と「実行結果」を突合する | 「N件起動」と言わせたら、N件の結果が揃うまで次へ進ませない。stop_reason="tool_use" を完了の証拠にしない |
| 最終成果物は対象母数で締める | 「全件処理」工程の後段で、対象集合との差集合がゼロであることを機械検証する |
| 事実ベースで報告する | 「できました」の一語で済ませず、実行結果(コマンド出力・テスト結果・リモートの状態)を添える。1項目でも未確認なら全体を未完として扱う |
まとめ
「XML露出」の実体はツール呼び出し要求と実行結果の不整合、および実行結果を伴わない成功報告という、二つの問題が重なった状態です。
ログから確実に言えるのは、stop_reason="tool_use" なのに実行可能な tool_use ブロックが記録に無いことまでです。
どの段階(モデル生成/ストリーミング/パース/保存)で不整合が起きたかは、このログだけでは特定できません。
最悪の症状は、未実行のまま成功を報告し、存在しないURL(404)を案内すること、そして処理した前提のサイレント欠落を残すことです。stop_reason だけ見ると成功に見えるため、無人運転ほど危険です。
守りの核心は3つです。
踏まない(少数ずつ実行する・複雑なコマンドを分割する・1テーマで区切る・早めに /compact する)
実測で検知(先頭の call/court・stop_reason×実行件数・結果の成功確認・リモート裏取り・母数照合)
出たら慎重に対応(実行済みと数えない・部分実行と外部状態を確認・冪等に再送、崩れが続けば新セッション)。
一行でまとめると:ツールを「呼んだこと」と「実行され、期待した結果が得られたこと」は別です。宣言ではなく結果を確認しましょう。
URLを貼る前に、そのURLの実在を確かめましょう。
お読みいただきありがとうございました。
また、次回お会いしましょう!
参考資料
公式ドキュメント
- How tool use works(Claude API Docs)― stop_reason: "tool_use" は実行の「要求」であり、クライアントが実行して tool_result を返す多段プロトコルであること。
- Effective context engineering for AI agents(Anthropic Engineering)― トークン数の増加に伴って精度や想起能力が低下する「context rot」の説明。
- Environment variables(Claude Code Docs)― 自動圧縮しきい値と CLAUDE_AUTOCOMPACT_PCT_OVERRIDE の仕様(既定は約95%、低い値で早められるが、既定より高い値には効果がない)。
Anthropic 公式リポジトリ上の利用者による不具合報告
これらは Anthropic の公式リポジトリに投稿されたものですが、内容は基本的に利用者による不具合報告であり、Anthropic が原因や再現条件を公式に認定した資料とは限りません(重複としてクローズされたものも含みます)。現象の観測例として参照しています。
- Issue #63870 ― Bash tool calls emitted as raw
<invoke>text instead of executing ― 生の<invoke>が通常テキストとして残り、コミット・push・PR作成などが実行されていなかった詳細ログ。 - Issue #64108 ― 先頭に紛れる court トークンに続いて生の
<invoke>が露出し、Edit/Read が実行されない報告(先頭の court が一貫した特徴とされる)。 - Issue #64690 ― Tool invocation XML tags intermittently corrupted ― ツール呼び出しタグ名が破損・露出して実行されない報告(重複としてクローズ)。
- Issue #68354 ― 先頭に call/court という素テキストが出たのち、XML風表現が露出し、ツールが実行されない報告。
- Issue #31806 ― CLAUDE_AUTOCOMPACT_PCT_OVERRIDE で既定より高い値を設定しても効かない(Math.min クランプ)ことを示す補助資料(重複としてクローズ)。
※ 本稿中の「同時3〜4体まで」「品質が落ちる前に圧縮」などの数値・運用方針は、Qualiteg としての暫定運用値であり、普遍的なしきい値ではありません。環境ごとに検証してご利用ください。