Failed compaction is retried unchanged on every turn: unbounded billed retries, monotonic context growth, no user-visible error
还没有人认领这个 Issue。
- 主要语言
- Shell
- 星标
- 11.2k
- 派生
- 1.9k
- 平均合并
- 14 小时 16 分钟
- 30 天内合并 PR
- 6
描述
Describe the bug
When a compaction model call fails, the CLI reissues the identical request on essentially every subsequent turn, with no backoff, no fallback, and no reconciliation of the payload that caused the failure. Each retry is a full billed model call, and because nothing is ever reclaimed, currentTokens grows monotonically until the session hits the hard context limit.
The failure is silent. Nothing appears in the transcript; success: false is only visible in session-state/<id>/events.jsonl. From the user's side the session simply "keeps compacting" and burns credits.
This is error-agnostic and therefore outlives any individual compaction bug. I hit it via a deferred-tool 400 on 1.0.81 (see below), which no longer reproduces on 1.0.82, but the retry behaviour itself is unchanged and still applies to the open compaction-400 reports #4519 and #4572.
Evidence
Two sessions on 1.0.81-3, from local events.jsonl:
| session | compaction_start | success | failed |
|---|---|---|---|
| A | 38 | 0 | 38 |
| B | 16 | 0 | 16 |
Every attempt returned the same error and the same toolDefinitionsTokens. Context across session A's retries, from session.compaction_start.data:
trigger=threshold currentTokens=750,933 -> 908,833 (tokenLimit 936,000)
38 consecutive billed calls, 0 tokens reclaimed, ~158k tokens of growth. The client never varied the request between attempts.
The originating error (for context)
compaction model call failed: HostRethrow {
message: "400 Tool reference '<redacted-mcp-tool>' not found in available tools"
}
The conversation history referenced an MCP tool that was not declared in the tools array sent with the compaction request. This occurred only while tool search / MCP tool deferral was active (toolDefinitionsTokens ~17.5k vs ~74k with the full catalogue).
The 400 itself no longer reproduces on 1.0.82. I ran 8 trials that each matched the failing shape exactly (deferral active, a deferred MCP tool present in history, automatic trigger: threshold compaction at ~160,800/200,000 tokens, toolDefinitionsTokens: 13,347); all 8 compacted successfully. Seven used one MCP server's tool; the eighth used the specific tool named in every original failure. Deferral was forced with toolSearch: true since the server-side flight is not under my control.
This report is about the retry behaviour, not that 400. The retry path is unchanged, and the same unbounded billed retry would follow from any other compaction failure.
Steps to reproduce
Any persistent compaction failure reproduces the retry loop. On 1.0.81-3:
- Run a session with an MCP server whose tools are deferred.
- Surface and call a deferred MCP tool.
- Let the session grow until
trigger: thresholdcompaction fires. - Observe
session.compaction_completewithsuccess: false, then the same request reissued on nearly every following turn.
Detect it in any session with:
python3 - <<'PY'
import json,glob,os
for p in glob.glob(os.path.expanduser('~/.copilot/session-state/*/events.jsonl')):
bad=ok=0
for line in open(p,encoding='utf-8',errors='replace'):
if 'compaction_complete' not in line: continue
try: e=json.loads(line)
except: continue
if e.get('type')!='session.compaction_complete': continue
d=e.get('data') or {}
if d.get('success') is False: bad+=1
elif d.get('success') is True: ok+=1
if bad: print(f"{p.split('/')[-2]} failed={bad} ok={ok}")
PY
Note the type check matters: tool.execution_complete and session.task_complete also carry success: true and appear on lines containing the string compaction_complete, which inflates the success count if you match the raw line.
Expected behavior
A failed compaction should not be retried unchanged and unbounded. Suggested, in order of value:
- Back off. Exponential backoff with a cap, and stop retrying after N consecutive identical failures.
- Surface it. A visible warning that compaction is failing and why. Today the only signal is credit burn.
- Reconcile or fall back. If the payload is structurally rejected, either repair it (for the case above: build
toolsfrom the union of the current catalogue and every tool referenced in the history being summarised) or fall back to hard truncation so the session can still reclaim context.
(3) is bug-specific; (1) and (2) are worth having regardless, and would have converted this from an invisible, unrecoverable credit drain into an actionable message.
Workaround
Resuming the session (copilot --resume=<id>) loads the full tool catalogue and lets compaction succeed. Both sessions above recovered this way, reclaiming 471,261 and 567,747 tokens. They were not permanently lost, but nothing in the UI suggests this.
Affected version
GitHub Copilot CLI 1.0.81-3 (retry loop observed)
GitHub Copilot CLI 1.0.82 (originating 400 no longer reproduces; retry path unchanged)
macOS darwin-arm64, model claude-opus-5, contextTier long_context
Related
- #4519 and #4572 are open compaction/deferred-tool 400s that would still trigger this retry loop.
- #4506 and #4639 are also compaction loops, but distinct: in those, compaction succeeds and reclaims nothing, or is driven by storage exhaustion. Here compaction hard-fails and is retried unconditionally.
贡献指南
从这里开始
- 先读完整个 Issue,再读项目的贡献指南。
- 在 Issue 下留言说明你要接手 —— 这能避免两个人做同样的事。
- Fork 仓库,在一个分支上完成修改。
- 提交 Pull Request,并在描述里引用这个 Issue 编号。
调研方向
针对 session-state//events.jsonl 运行提供的 Python 扫描,并检查显示重复失败的 compaction_complete 事件。跟踪重试失败 compaction 的 CLI 路径,然后验证重复的相同失败会受到限制或采用退避机制,并且用户会收到可见警告,而不是静默执行消耗 credit 的重试。
由索引模型根据 Issue 内容生成。
评估
- 技术栈
- shell
- 领域
- cli
- Issue 类型
- 缺陷
- 难度
- 4/5
- 预计耗时
- 3-5 天
- 活跃度
- 活跃
- 描述清晰度
- 基本清楚
- 新手友好度
- 52/100