来源:arte.itlibra.com
原文:https://arte.itlibra.com/en/articles/claude-code-court-invoke-tool-call-error
一句话:Claude Code 用户可能突然看到终端里出现一个毫无意义的词court,后面跟着一串<invoke>标签。这不是你搞错了什么——这是一个模型侧的生成 bug,而且最危险的不是它「出错」,而是它会「传染」。
一、现象:你的终端突然说「court」
如果你用 Claude Code 做过长会话,可能遇到过这种诡异场景:
court
<invoke name="Bash">
<parameter name="command">ssh host 'cp file file.bak ; sed -i ...'</parameter>
<parameter name="description">…description of the command…</parameter>
</invoke>
Your tool call was malformed and could not be parsed. Please retry.
一个应该在后台静默执行的 Bash 命令,突然以原始 XML 的形式泄露到了你的屏幕上。前面还莫名其妙地站着一个单词:court(或者 call)。
你的第一反应可能是:
- 我环境配置错了?
- 我的命令写坏了?
- Claude 被黑了?
答案:都不是。这是 Claude(特别是 Opus 4.8/4.7 家族)的一个已知模型侧生成 bug。
Anthropic 官方仓库里堆满了关于这个问题的 issue:#64108、#64150、#64690、#65705、#66153、#67295、#68354……多到可以开一个专题了。
二、技术机制:工具调用不是 API 调用,而是「文本生成」
你以为的过程
用户:帮我备份文件
Claude 内部:调用 Bash 工具 → 执行 → 返回结果
你看:备份完成
实际的过程
用户:帮我备份文件
Claude 内部生成文本:
"让我先备份文件……
<invoke name="Bash">
<parameter name="command">cp file file.bak</parameter>
</invoke>"
Claude Code(客户端):解析这些 XML 标签 → 提取命令 → 实际执行 → 把结果塞回对话
你看:备份完成
关键洞察:工具调用对 Claude 来说,本质上就是生成一段带有特殊控制标签的文本。这些标签(<invoke>、<parameter>)和普通的英文单词一样,都是一个一个 token 生成出来的。
正常情况下,客户端(Claude Code)会解析这些标签,提取命令执行,然后把执行结果呈现给用户。标签本身永远不应该出现在屏幕上。
当 court 出现——控制 token 损坏了
问题出在这个序列的第一个控制 token。在生成 <invoke 这个标签的时候,模型因为某种采样抖动,生成了一个相邻的 token——court(或者 call)——而不是正确的标签开头。
结果,整个工具调用的「信封」被破坏了:
原本应该是:
<invoke name="Bash">...
实际变成了:
court
<invoke name="Bash">...
Claude Code 的解析器看到 court 开头,不认识这是什么东西,判定「这不是一个工具调用,只是普通文本」,于是直接把它流式输出到屏幕。
命令没有执行。没有安全风险。因为解析器是「fail-closed」的——不认识就拒绝,而不是猜着执行。
三、为什么这个 bug 不是小事:「链式反应」
如果事情只是「偶尔出现一个 court,然后重试就好」,那这个问题不值得专门写一篇文章。
真正的问题是:这个 bug 会传染。
核心机制:Self-Poisoning(自我污染)
当一个破损的工具调用块留在对话历史中,Claude 在后续生成时,会把它当成一个「正确的示例」来模仿。也就是说:
第一轮:模型偶然生成了 court + 破损调用
第二轮:模型看到历史里有 court + 破损调用,认为「这是正确的格式」
第三轮:模型再次生成 court + 破损调用
第四轮:……
Issue #64150 和 #62344 记录了这种现象:一旦链式反应开始,重试不会修复,而是让错误模式被不断强化。
真实案例
- Issue #65705:用户在一个 1,739 行、持续 3 天的会话中,连续遇到 14 次失败
- Issue #66153:一个会话中连续 30+ 次失败
这就是为什么文章给出的铁律是:
Miss twice, bail to a fresh session.
出错一次,可以重试一次。连续出错两次,立刻/clear开新会话。
四、触发条件:什么情况下容易中招?
根据 issue 的统计,以下场景会提高触发概率:
- 超长会话:多天的持续会话,百万级上下文(#65705:1,739 行,3 天)
- 单次消息多个工具调用:一次请求里塞了太多工具调用
- 工具调用紧跟在 prose 后面:文本和工具调用混在一起
/compact后:压缩上下文后的第一次调用(#67295)- 后台 Bash(run_in_background) 或 3+ 个 MCP 服务器 连接(#64690)
- 超长的工具参数:参数长度达到段落级别(#49747)
结论:触发条件是**「高复杂度环境」,但根本原因是模型侧采样时的 token 生成错误**,不是用户做错了什么。
五、修复策略:用户和开发者该怎么做
用户侧(Claude Code 用户)
优先级 1:立即开新会话(/clear)
当 court 出现时,不要犹豫,/clear 或新会话。切断被污染的对话历史是最可靠的修复。
优先级 2:重试一次(仅适用于首次出错)
如果这是第一次出现,且之前会话一直正常,可以打字「resume」或「continue」让模型重新生成。但如果连续两次失败,立刻执行优先级 1。
优先级 3:避免高危模式
- 不要在一个会话里跑多天的任务
- 不要把太多工具调用塞进一条消息
- 不要依赖
/compact作为万能修复(它有时反而触发问题) - 经常用
git commit或.md交接笔记保存状态,这样随时切换会话无成本
开发者侧(使用 Claude API/SDK 构建 Agent)
如果你是开发者,在自己的 harness 中可以增加以下防御:
// 检查收到的 assistant 回复中是否泄露了工具调用标记
const text = assistantText(resp);
const looksLeaked =
/<invoke\s+name=/.test(text) ||
/function_calls/.test(text) ||
/\bcourt\s*<invoke/.test(text);
if (looksLeaked && !hasToolUseBlock(resp)) {
// 1. 不要展示给用户
// 2. 不要保留在对话历史中(防止 self-poisoning)
// 3. 提示模型重新以结构化 tool_use 格式生成
return retryWithNudge(messages);
}
// 检查 stop_reason:如果 max_tokens 截断在 tool_use 块中间,不要执行
if (resp.stop_reason === 'max_tokens' && lastBlock(resp)?.type === 'tool_use') {
return retryWith({ max_tokens: higher });
}
四个核心原则:
- 始终检查
stop_reason - 检测文本中的
<invoke name=或function_calls泄露,发现则重试 - 不要把破损的调用块留在对话历史中
- 保持工具参数简短,避免长 payload 变体
六、常见误解纠正
| 常见误解 | 真相 |
|---|---|
| 「工具失控了,命令可能乱执行」 | 相反。 破损调用被判定为 malformed,拒绝执行(fail-closed)。没有命令会运行,没有安全风险。 |
| 「重试就行,它会自愈」 | 只对一半。 首次出错重试通常有效,但一旦链式反应开始,同会话内重试会加深污染。 |
「court 有特殊含义,是某种命令」 |
没有任何含义。 只是损坏控制 token 的「签名」。但它作为诊断标记很有用——看到 court 就知道是这个 bug。 |
七、官方状态:截至 2026 年 6 月,尚无确认修复
这是一个令人不安的事实:
截至 2026 年 6 月,没有官方 changelog 确认这个问题已被修复。
Claude Code 的 2.1.183 版本及之前,没有针对工具调用序列化损坏的修复条目。大量相关 issue 仍被标记为 open 或 duplicate/stale。
但这里有一个关键的安全设计值得肯定:Claude Code 的解析器是「fail-closed」的——拒绝执行一个损坏的调用,而不是试图猜着修复并执行。后者会更危险:如果解析器「聪明地」修复了一个损坏的命令并执行,它可能运行一个错误甚至恶意的命令。
需要修复的是模型的生成稳定性,而不是放宽解析器的严格性。
八、延伸:这与 MCP 生态的关系
MCP(Model Context Protocol)是 Anthropic 推动的 Agent 工具标准,正在被广泛采用。这个 bug 之所以重要,不仅因为它影响 Claude Code,更因为:
- MCP 工具调用的底层也是同样的机制:模型生成控制标签,客户端解析执行
- 如果 Claude 的 Opus 家族在这个基础机制上有稳定性问题,任何基于 MCP 的 Agent 框架(OpenCode、Codex 等)如果接入相同模型,理论上都可能遇到类似问题
- harness 设计的「fail-closed」原则,是所有 Agent 框架应该学习的安全模式
九、结语:一个「无害但烦人」的 bug,教会我们的工程课
Claude Code 的 court bug 看起来很小:一个无意义的单词,一次失败的工具调用,重试或刷新就解决。
但它揭示了几个重要的工程原则:
-
Fail-closed 是底线:不认识就拒绝,比猜着执行更安全。Claude Code 的解析器在这个 bug 上表现出了正确的安全设计。
-
Self-poisoning 是对话系统的隐形杀手:错误留在历史里会被模仿,这解释了为什么「重试」有时反而让问题更糟。
-
Context 是双刃剑:长上下文给了模型更多能力,但也给了错误更多「复制模板」的机会。
/compact不是万能药,对话历史的清洁度可能比上下文长度更重要。 -
模型侧的「微小」生成错误,可以放大为用户侧的「系统性」故障:一个 token 的采样抖动(
courtvs<invoke),最终可能导致 30+ 次连续失败。
对于 Claude Code 用户,记住这个规则就够了:
看到
court→ 重试一次 → 再失败 → /clear → 保存状态 → 新会话。
对于开发者,记住这个防御模式:
检测泄露 → 拒绝保留 → 重试重新生成 → 永远不要猜着执行。
参考信息
- 原文分析:https://arte.itlibra.com/en/articles/claude-code-court-invoke-tool-call-error
- 相关 Issue:Anthropic 官方 #64108, #64150, #64690, #65705, #66153, #67295, #68354
- 影响模型:Claude Opus 4.8 / 4.7 家族
- 关键概念:Fail-closed harness、Self-poisoning、Tool-call generation corruption
- 官方状态:截至 2026-06 无确认修复,workaround 阶段
#ClaudeCode #MCP #ToolCall #Anthropic #AI安全 #FailClosed #SelfPoisoning #Bug分析 #小凯
讨论回复
加载中...正在加载回复...
推荐
智谱 GLM-5 已上线
我正在智谱大模型开放平台 BigModel.cn 上打造 AI 应用,智谱新一代旗舰模型 GLM-5 已上线,在推理、代码、智能体综合能力达到开源模型 SOTA 水平。