一行代码修复 DCP 别名泄漏:一次human-agent协作的调试记录

June 17, 2026

问题

Message ID alias capacity exceeded.
Cannot allocate more than m9999 aliases in this session.

@tarquinen/opencode-dcp 在我的 OpenCode session 里频繁崩溃。每次报这个错,就只能开新 session,用一段时间又崩。

第一步:判断泄漏

拿到这个错误信息后,我的第一反应是:肯定是哪里有问题, 9999 是一个很大的数字,我没有在这个 session 里对话 9999 条消息。如果它满了,说明可能存在泄漏。而且按这个速度,大概率每次消息往返都在漏。

顺着这个思路,我让 AI 从源码开始找。

第二步:定位泄漏

AI 搜索 assignMessageRefs 的调用位置,在 lib/hooks.tscreateChatMessageTransformHandler 管线中找到了问题顺序:

assignMessageRefs → prune → injectMessageIds

assignMessageRefs 跑在 prune 之前,意味着所有消息先被分配 alias,然后 prune 删掉一部分消息——但已分配的 alias 留在 state.messageIds 里,再也没人清理。

泄漏路径确认。每次 assistant 回复进入管线,都产生一批孤儿 alias,只增不减。

第三步:验证移动安全性

确定了根本原因是顺序问题后,我的第一个追问是:移后会不会破坏上下游?

AI 检查了 assignMessageRefsprune 之间的三个函数:

函数 依赖 state.messageIds 证据
syncCompressionBlocks 操作的是 state.prune.messages.blocksById(block ID ↔ 消息 ID 映射),不涉及 alias ref
syncToolCache 遍历 output.messages 扫描 tool_use/tool_result 类型的 part,只关心 tool call ID(msg_call_xxx
buildToolIdList syncToolCache 的结果建索引,不碰 alias

三家都不依赖。移动安全。

第四步:验证覆盖完整性

我的第二个追问:会不会有消息因此拿不到 alias?

这个追问把 AI 带进了 prune 内部的 filterCompressedRanges。它做两件事:删除已被压缩的旧消息、创建一个新的合成摘要消息(createSyntheticUserMessage)。

在旧顺序下,合成消息创建在 assignMessageRefs 之后——它没有 alias。这其实是旧顺序的另一个 bug。

在新顺序下:

  • 删旧消息 → 从未分配 alias → 零泄漏
  • assignMessageRefs 跑在 prune 之后 → 合成消息也能拿到 alias

双重改善。这个追问没有发现风险,反而发现了一个被忽略的覆盖缺漏。

修复

-  assignMessageRefs(state, output.messages)
   syncCompressionBlocks(state, logger, output.messages)
   syncToolCache(state, config, logger, output.messages)
   buildToolIdList(state, output.messages)
   prune(state, logger, config, output.messages)
+  assignMessageRefs(state, output.messages)

验证

我要的不是"看起来没问题"——我要一个可复现的测试。RED→GREEN:构造有多条消息且经过完整管线的场景。旧顺序下 nextRef 明显增长(alias 被白白分配),新顺序下 alias 只分配给幸存消息。AI 写测试前这个断言对旧代码 FAIL、对新代码 PASS。

全部 87 个已有测试通过。

merge

alt text

总结

这次调试的关键推进来自几个判断和追问,这也是人的价值:

  • "应该是泄漏"——把方向从症状修引向根因
  • "确认依赖关系"——防止了"看起来没问题"式盲猜
  • "会不会有东西没被 assign"——发现了旧顺序下合成消息缺 alias 的双重问题
  • "写 RED→GREEN 测试"——让修复可验证、可追溯

PR 被合并。改动:一行。


Profile picture

Written by Prosumer , an undergraduate student at ShanghaiTech.
Welcome to my GitHub:)