What Is That "court" in Claude Code? The "XML Leak" Phenomenon and Guarding Against Unexecuted Tool Calls
Hello!
This is the Qualiteg Product Development Team.
When you use Claude Code, the raw tool-call XML (<invoke> or <parameter>) sometimes appears verbatim on screen, or the assistant reports "done" even though no command actually ran and no PR was actually created — and things start behaving strangely.
And the trigger strings court or course or count show up as well.
In this article,
we examine this phenomenon (referred to here as the "XML leak") using real logs, and summarize how to detect and counter it.
Or, as below, course may appear.
course
<invoke name="Bash">
<parameter name="command"</parameter>
<parameter name="description">xxx</parameter>
</invoke>
There are also cases where count leaks out, like this.

And sometimes it looks like a runaway, as here...

court, course, count or raw <invoke> is on your screen right nowWhen using Claude Code, on rare occasions XML-like strings such as <invoke> and <parameter> are displayed as-is in the conversation view.
If it were only a matter of broken formatting, it might seem like a mere display bug. The real issue is that the
tool operation those strings were meant to represent may not actually have been executed at all
.
File edits, shell commands, subagent launches, PR creation — none of it happened, and yet subsequent responses may proceed on the assumption that it is "done."
For convenience, this article calls the phenomenon an "XML leak." (This is not an official incident name.)
Based on actual session logs, we will sort out what could be observed, where inference begins, and what should be verified in day-to-day operation.
Notably, very similar phenomena have been posted multiple times as user bug reports on Anthropic's official Claude Code repository.
raw <invoke> displayed as text; stop_reason="tool_use" with no corresponding tool_use in the record; and, as a result, commits and PRs that were never created、
— reports along those lines.
With multiple similar reports, this does not look like an accidental display glitch confined to individual environments.
As of this article's publication (June 2026), we could find no official changelog entry stating that the phenomenon has been fixed, and many of the related issues (#63870 / #64108 / #64690 / #68354, among others) remain open or closed as duplicates.
Please treat every remedy introduced in this article as a workaround while an official fix is awaited.
1. We Call This Phenomenon an "XML Leak"
"XML leak" is this article's convenience term for the phenomenon in which XML-like markup apparently intended for tool calls (<invoke>, <parameter>, and so on) leaks into the body text, and the corresponding operation either is not executed or can no longer be confirmed to have executed normally. It is not an official name.
A leak does not always mean non-execution; what can be said with certainty is that "you can no longer determine whether it was processed as a normal tool call."
(The recovery steps described later rest on this premise.)
The key is to see this as two problems overlapping.
(1) An inconsistency in the tool-call pipeline ... the model's output cannot be confirmed in the record as a structured tool_use block, and no corresponding execution result can be confirmed either.
(2) Conflating the call with completion ... assuming the operation ran, subsequent model output generates prose saying "done."
(1) is difficult to prevent completely through user-side practices alone.
That is precisely why cutting off (2) — not trusting the output (the declaration) and verifying against execution results — becomes the heart of the countermeasures. And because an "XML leak" is immediately visible, it can be used as an early-warning canary for tool-call pipeline anomalies.
2. How a Normal Tool Call Works
First, let us review the mechanism when everything works correctly.
Under the Claude API's published specification, for client tools (tools executed on the caller's side, such as Bash or file edits), when the model wants to use a tool, the response comes back with stop_reason: "tool_use" and one or more tool_use content blocks.
The client side (the execution harness) reads those blocks, runs the actual tools, and returns the results as tool_result blocks.
The model receives those results and generates the continuation.
(Server tools such as web search are executed on Anthropic's side, so this does not apply to them. This article deals with client tools.)
The important point is that "requesting the tool," "executing the tool," and "confirming the result" occur as separate stages.
stop_reason: "tool_use" is merely metadata indicating that the model is requesting execution — it is not evidence that the tool was executed
(see How tool use works for the details).
Meanwhile, XML-like notations such as <function_calls> and <invoke> are not formats guaranteed by the Claude API's published specification.
They appear to be internal representations of the Claude Code family, or serialized forms that surface on failure. Accordingly, this article's scope is not "LLM agents in general" but the phenomenon as observed in Claude Code and Claude-family agents.
(The normal flow on the public API)
Model: stop_reason="tool_use" + tool_use block(s) ← the "request" to execute
↓
Client: reads the tool_use and actually executes it
↓
Client: returns a tool_result ← the "result" of execution
↓
Model: receives the result and generates the continuation
An "XML leak," then, corresponds to a state in which — somewhere in this flow — the tool call cannot be confirmed in the record as a structured tool_use block, and no corresponding execution result can be confirmed either.
3. What Was Happening in the Actual Logs
The environment where it occurred (measured values) was as follows.
| Item | Value |
|---|---|
| Claude Code version | 2.1.179 (Claude Code) |
| Model used | claude-opus-4-8[1m] |
| Extended (1M) context | Enabled (model ID suffix [1m]; /context shows "… / 1m tokens") |
| OS / terminal | Windows 11 family (10.0.26200.8246); shell is Git Bash/MSYS (MINGW64_NT-10.0-26200) |
| Environment variables | CLAUDE_AUTOCOMPACT_PCT_OVERRIDE unset / ANTHROPIC_MODEL unset (default behavior in both cases) |
Measured /context around the occurrence |
About 55% (549.7k / 1M tokens) |
* These do not mean "the same environment will always reproduce it" — they are simply the conditions at the time of observation.
In particular, the fact that it occurred with Opus 4.8's 1M context enabled and context usage at roughly half (about 55%) is worth recording in light of the context-rot hypothesis discussed later (§5).
The setting was a session launching subagents in parallel "waves" of four, working through many tasks in order. Waves 1 through 6 were fine. The problem struck at wave 7.
3-1. The log where XML leaked into the body text
First, this is what the user sees on screen. Tool calls that should run behind the scenes are displayed verbatim as plain strings
(at this point, there is no telling whether these operations executed normally)
Wave 6 complete. Launching wave 7 (tasks 0001-0004).
court
<invoke name="Task">
<parameter name="description">Job 0001</parameter>
<parameter name="subagent_type">general-purpose</parameter>
<parameter name="prompt">You are a task-execution agent. Target: task-0001. ... (long prompt) ...</parameter>
</invoke>
<invoke name="Task"> ...0002... </invoke>
<invoke name="Task"> ...0003... </invoke>
<invoke name="Task"> ...0004... </invoke>
Viewed as the record (the transcript), it looked like this.
{
"role": "assistant",
"content": [
{
"type": "text",
"text": "Wave 6 complete. Launching wave 7 (tasks 0001-0004).\n\ncourt\n<invoke name=\"Task\">\n<parameter name=\"description\">Job 0001</parameter>\n<parameter name=\"subagent_type\">general-purpose</parameter>\n<parameter name=\"prompt\">You are a task-execution agent. Target: task-0001. ... (long prompt) ...</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 }
}
What this log lets us read off:
The content type is "text" — the block of <invoke ...> is recorded not as a structured tool_use block but as plain body text. And yet stop_reason is "tool_use" — per the response, it "stopped while requesting tool execution."
As a trace of the breakage, the XML-like fragment begins abruptly at <invoke>, and just before it you can also see the dangling word court left hanging on its own.
Four consecutive <invoke name="Task"> entries — it was evidently trying to launch four subagents with long prompts in parallel at once.
* The stray plain-text court at the head (in some environments, call) is not a fluke unique to this article; in bug reports on the official repository it is repeatedly observed as the sign appearing just before a tool call fails to execute and raw <invoke> leaks out (Issue #64108 / #68354).
The demo at the top of this article shows the same phenomenon with a Bash call; leaked tools are reported across multiple kinds — not just Task but Bash, Edit, Read, and others — and our wave-7 example (parallel Task launches) appears to be one form of it.
3-2. The log where the tool call left no record
This is the turn immediately after (the reissued attempt).
{
"role": "assistant",
"content": [
{ "type": "text", "text": "Launching subagent wave 7 (tasks 0001-0004)." }
],
"stop_reason": "tool_use",
"usage": { "output_tokens": 3609 }
}
content contains only the one-sentence preamble — not a fragment of <invoke> anywhere.
Yet stop_reason is "tool_use" and output_tokens is 3609. The mismatch between stop_reason and content ("stopped while requesting tool execution," yet not a single executable tool_use block in the record) looks like the heart of this phenomenon.
This cannot be explained by "the model accidentally wrote it into prose." The first case, where the XML was visible, is the "partially leaked" manifestation; the second, where nothing was visible, is the "never recorded" manifestation — plausibly two faces of the same inconsistency.
Note that output_tokens can include not only the displayed text but also thinking (extended reasoning) tokens, so the number 3609 alone is not grounds to conclude hastily that "thousands of tokens of tool calls vanished."
What matters, then, is not the token count but the inconsistency between stop_reason="tool_use" and the recorded content blocks.
4. What the Logs Do and Do Not Tell Us
Here, let us separate what the logs allow us to assert from what they do not.
We do not want to jump to conclusions about the cause, so let us lay it out.
| Category | Details |
|---|---|
| Observed facts | XML-like tags were recorded as text / stop_reason="tool_use" yet no executable tool_use block / no corresponding execution result can be confirmed |
| Facts from the spec | stop_reason="tool_use" is the "request" for execution, not the "result" / execution and its confirmation are separate stages |
| Inference | The inconsistency arose at some stage — model generation, streaming conversion, SDK/CLI parsing, or transcript persistence (which one cannot be determined) |
| Operational hypothesis | Long content, parallelism, and complex arguments may raise the incidence (an observation-based hypothesis) |
In short, what this log lets us say for certain is only that
the recorded response contains no structured tool_use block, and no corresponding tool_result can be confirmed.
Whether the model failed to generate a correct call, whether it was lost in streaming or parsing, or whether it went missing when saved to the transcript — this log alone cannot determine.
This article therefore does not pin the cause down as "a capture failure on the harness side" and stays with the phrasing
"an inconsistency in the tool-call pipeline can be confirmed"
.
5. Why This Is Operationally Dangerous
The essence of the danger is not the visual mess but the divergence in progress.
Looking at the execution record
stop_reason="tool_use", yet no corresponding structured tool_use or tool_result
→ you cannot confirm the operation executed normally.
Looking at the subsequent model output
the prose continues on the assumption the operation completed
→ it moves on as if the result had come back.
In this particular case, after cross-checking subsequent state and deliverables, we judged that the target tasks had not been executed
(we treat the general "cannot confirm" and this case's measured "was not executed" as separate things).
This divergence produces two kinds of accidents.
(1) Success reports with no execution results behind them
This is especially problematic for operations with side effects.
gh pr create call is generated.
But it is never handed over as an executable tool_use, and it does not run.
Even so, the subsequent response says "Created the PR," believes the PR exists, and presents a plausible-looking URL.
But when the user clicks it: 404.
No such PR exists.
Reporting "it worked / it's done" as prose rather than as an execution result is the greatest harm.
(2) Silent omission (unprocessed work assumed processed)
In batch processing,
"wave 7 was assumed launched when in fact not a single agent ran, and the session moved straight on to wave 8"
— that kind of quiet dropout can occur.
"Wave 7 complete" is displayed
→ in reality, tasks 0001–0004 are unprocessed
→ downstream steps proceed assuming "everything was done"
→ four items go silently missing from the final deliverable.
In the §3 logs, we were ultimately saved
(wave 7 was resent immediately afterward, and the target tasks appeared in sequence over the following turns — recovery succeeded).
But if you fail to notice, the omission quietly remains — and since stop_reason alone makes it look like success, the more automated and unattended the operation, the greater the danger.
Why long, parallel sessions seem more prone to it
The phenomenon of instruction-following and recall degrading over long context — "context rot" itself —
is described in Anthropic's official materials as accuracy and recall declining as token counts grow
(Effective context engineering for AI agents).
There are multiple reports of "XML leaks" occurring in long, tool-heavy sessions, which is consistent with the hypothesis that instruction-following and structural integrity grow unstable under long context.
That said, there are also reports of it occurring right at session start, and reports suspecting a connection to parallel tool calls or tool configuration.
Accordingly, an "XML leak" can be used as an early warning of session-quality degradation.
However, given the reports in short sessions as well, context rot cannot be treated as the sole cause. The sound framing is this: an "XML leak" is more accurately a canary for tool-call pipeline anomalies than a canary for context rot.
6. Detection, Recovery, Prevention
6-1. Detection (diagnostics)
Detection first.
Leaks you can see, you will notice. What is worrying are the forms that leave no record, and success reports with no execution behind them — so detect mechanically and empirically, without relying on appearances. The principle: judge completion by results, not declarations.
| Detection signal | What to look at | Anomaly / pass condition |
|---|---|---|
| Cross-check stop_reason against tool_use | The response's stop_reason and the count of executable tool_use blocks |
stop_reason=="tool_use" with zero tool_use blocks → anomaly |
| Detect stray leading text | The standalone line immediately before a tool call | Flag call / court as a precursor to a leak |
| Match declared vs. executed counts | The "launching N" declaration vs. actual tool_use/result counts |
Count differs from N → anomaly |
| Raw tags in the body text | The response's body text | Flag immediately if <invoke / <function_calls / <parameter appears |
| Judge completion by results | Presence and content of tool_result | Complete only when all of: ① request → ② tool_result returned → ③ success indicated → ④ expected external state |
| Remote verification of side-effect operations | The actual push/PR/merge/deployed artifact | Confirm SHA match / gh pr view state / file existence via git ls-tree. Verify a URL exists before pasting it |
| Reconcile against the full target set | Target set vs. the set for which outputs were produced | After any "process everything" step, machine-check that the difference set is zero |
| Watch for co-occurring signs | Repeated explanations / re-asking settled decisions / declarations without execution | Signs of quality decline in that session — inputs for tightening verification or ending the session |
6-2. Recovery (once it has happened)
Some operations are dangerous, so proceed with care.
・PR / push →
gh pr view <number> --json url,state / git ls-remote origin <branch>・File edits → open the target file and visually confirm the changes are there
If it breaks twice in a row: abandon that session, note down the state, and move to a new session (
/clear).
Now, as the box above says,
the leaked call itself is usually unexecuted, but
・another tool in the same turn may have executed first, or
・part of a parallel batch may have actually run
(with parallel calls, there are also reports of a single failure causing sibling calls to be cancelled).
Unconditionally re-running PR creation, deploys, charges, or email sends risks double execution, so check external state first and move carefully.
| # | Step | Point |
|---|---|---|
| 1 | Do not count the leaked call as executed | Treat anything that appeared as XML on the premise it "most likely did not run" |
| 2 | Check the current external state | Check for partial execution, including other operations in the same turn |
| 3 | Retry only after confirming non-execution | Narrow to a single operation. Split long arguments and parallel multi-tool calls. Use an idempotent form if possible |
| 4 | Verify before re-running side-effect operations | Check unique IDs / external state before retrying, to prevent double execution |
| 5 | If the breakage continues, end the session | Do not pile more onto a broken state. Externalize the state into a handover document and start over in a new session |
Roughly speaking, the sound approach is: verify whether the command shown in the leaked XML really executed (it most likely did not), have the session produce a handover document, and end that session early.
That said, when the symptoms are severe it cannot even produce a handover document. In such cases, it is also effective to
① copy and paste the session log where the XML leak occurred, then
② tell the new session, "the previous session was cut short by this incident — please continue from where it left off"
.
6-3. Prevention (before it happens)
The suspected incidence-raisers are long content, parallelism, and complex arguments. Break requests into small pieces, and — before quality declines — cut the session, compact, and move state outside. Those are the pillars of prevention.
| Preventive measure | Aim / how |
|---|---|
| Do not fire heavy parallelism and long parameters at once | Cap the number of concurrent subagents with long prompts (rule of thumb: 3–4 at most) |
| Do not bundle everything into one giant command | Split long regexes, heredocs, Windows paths, and the like into script files to lower escaping density |
| Do not pack explanation and execution into the same request | Do not send a long explanation plus many operations in one go; issue them separately |
| Limit the operations requested at once | Execute and verify critical side-effect operations (PR creation, deploys, etc.) one at a time |
| One session = one theme; cut early | At the cut, commit the results, then clear the conversation or start a new session |
| Compact manually (/compact) before quality declines | Compact after the decline and the confusion gets summarized in along with everything else, making things worse |
| Always externalize state | The habit of writing a "handover document plus next-run work order" each time is the royal road against context rot |
6-4. Structural Defenses (Design and Operations)
Rather than relying on individual caution, build into the operating loop itself a "gate that reconciles declarations with results." The premise: never treat stop_reason as evidence of completion.
| Design principle | Concrete measure |
|---|---|
| Reconcile "launch declarations" with "execution results" | If it declares "launching N," do not let it advance until N results are in. Never treat stop_reason="tool_use" as evidence of completion |
| Close out final deliverables against the full target set | After any "process everything" stage, machine-verify that the difference against the target set is zero |
| Report on a factual basis | Never settle for a one-word "done"; attach execution results (command output, test results, remote state). If even one item is unverified, treat the whole as incomplete |
Summary
The substance of an "XML leak" is two overlapping problems: an inconsistency between the tool-call request and its execution results, and success reports with no execution behind them.
What the logs let us say for certain is only that stop_reason="tool_use" appears with no executable tool_use block in the record.
At which stage the inconsistency arose (model generation / streaming / parsing / persistence) cannot be determined from these logs alone.
The worst symptoms are reporting success without execution and presenting a nonexistent URL (404), and leaving silent omissions behind under the assumption the work was done. Since stop_reason alone makes it look like success, unattended operation is where the danger peaks.
The core of the defense is threefold.
Do not step on it (execute a few at a time, split complex commands, keep one theme per session, /compact early)
Detect empirically (the leading call/court, stop_reason vs. execution counts, confirming successful results, remote verification, reconciling against the full set)
Respond carefully once it appears (do not count it as executed; check for partial execution and external state; resend idempotently; move to a new session if the breakage continues).
In one line: "calling" a tool and "it executed and produced the expected result" are different things. Verify results, not declarations.
Before pasting a URL, confirm that the URL actually exists.
Thank you for reading.
See you next time!
References
Official documentation
- How tool use works (Claude API Docs) — stop_reason: "tool_use" is the "request" for execution, part of a multi-stage protocol in which the client executes and returns tool_result.
- Effective context engineering for AI agents (Anthropic Engineering) — the explanation of "context rot," in which accuracy and recall decline as token counts grow.
- Environment variables (Claude Code Docs) — the auto-compaction threshold and the CLAUDE_AUTOCOMPACT_PCT_OVERRIDE specification (default around 95%; lower values move it earlier, but values above the default have no effect).
User bug reports on Anthropic's official repository
These were posted to Anthropic's official repository, but they are essentially user-filed bug reports, and are not necessarily materials in which Anthropic has officially confirmed causes or reproduction conditions (some are closed as duplicates). We reference them as observed instances of the phenomenon.
- Issue #63870 ― Bash tool calls emitted as raw
<invoke>text instead of executing — a detailed log in which raw<invoke>remained as ordinary text, and commits, pushes, and PR creation had not been executed. - Issue #64108 — a report in which the stray leading court token is followed by raw
<invoke>leaking out, with Edit/Read not executed (the leading court is described as a consistent signature). - Issue #64690 — Tool invocation XML tags intermittently corrupted — a report of tool-call tag names corrupting and leaking without execution (closed as a duplicate).
- Issue #68354 — a report of the plain text call/court appearing first, followed by leaked XML-like notation and unexecuted tools.
- Issue #31806 — supporting material showing that setting CLAUDE_AUTOCOMPACT_PCT_OVERRIDE above the default has no effect (a Math.min clamp) (closed as a duplicate).
* Figures and operating policies in this article, such as "3–4 concurrent at most" and "compact before quality declines," are Qualiteg's provisional operating values, not universal thresholds. Please validate them in your own environment.