"OpenClaw 浏览器发帖链路故障复盘:从 fields are required 到 stale ref 的系统级修复"

OpenClaw 浏览器发帖链路故障复盘:从 fields are required 到 stale ref 的系统级修复

这篇文章是一次真实线上排障的完整复盘,目标是把「为什么会炸、为什么之前没问题、这次到底改了什么」讲清楚,并给出可重复执行的修复步骤。

适用人群:

  • 在 OpenClaw 中使用 browser 工具自动化发帖/填表的人
  • 遇到过 fields are requiredElement \"eXX\" not found or not visibleNo tool call found for function call output ... 的人
  • 想把一次“临时救火”升级为“稳定可复用修复方案”的人

一、现象与业务影响

1) 主要报错

在本次故障中,出现了三类典型错误:

  1. fields are required
  2. Element "e92" not found or not visible. Run a new snapshot to see current page elements.
  3. 400 No tool call found for function call output with call_id ...

2) 业务表现

  • 页面能打开
  • DOM 能 snapshot
  • 一到 act/fill 或节点输入动作,browser 控制服务报错中断
  • 导致跨站发帖流程(Linux.do / V2EX / 2libra / iSharkFly)无法连续执行

这类故障很容易误判成“账号权限问题”或“上下文太长”,但本次证明并非如此。


二、时间线(关键节点)

  • 2026-02-23 12:44(CST)左右:本机 OpenClaw 安装/更新到 2026.2.22-2
  • 之后出现大量 browser 报错:fields are required
  • 进一步推进后,出现 stale ref:Element "e92" not found or not visible
  • 历史会话中存在:No tool call found for function call output ...
  • 最终通过协议兼容 + stale ref 兜底修复后恢复成功发帖

说明:

  • No tool call found ...fields are required 不是同一个问题。
  • 降低上下文窗口(比如 1048576 → 200000)不能直接修掉这两个底层错误。

三、根因拆解

根因 A:fill 协议不兼容(最先引爆)

上游动作请求常见形态是:

{
  "kind": "fill",
  "ref": "e57",
  "text": "..."
}

而当前路由实现更偏向要求:

{
  "kind": "fill",
  "fields": [
    { "ref": "e57", "type": "text", "value": "..." }
  ]
}

fields 未提供且没有兼容映射时,就直接触发 fields are required

根因 B:动态页面导致 ref 漂移(stale ref)

例如:

  • snapshot 时拿到 e92
  • 页面组件重绘/弹层切换后,e92 已失效
  • 后续 type/fill 仍拿旧 ref 执行,触发 not found or not visible

这在 V2EX 节点选择输入框等动态 UI 非常常见。

根因 C:No tool call found ... 是会话调用状态错位

该错误属于 session/tool-call 链路不一致(call_id 对不上),不是浏览器 DOM 操作失败本身。


四、修复目标与策略

目标不是“单点补丁”,而是把发帖链路做成“兼容 + 自愈 + 可观测”:

  1. 兼容旧请求形态,避免 fields are required
  2. stale ref 自动恢复,不要求人工每次重 snapshot
  3. 第二次失败仍有兜底,不让流程在关键写入点直接崩

五、实际改动(运行时 dist)

说明:OpenClaw 打包后存在多份 hash 产物,必须同步补齐关键分支,避免运行时命中未修补 bundle。

1) fill 兼容层

/actcase "fill" 中加入兼容映射:

  • fields 缺失时,自动将 {ref,text/value} 转为 fields:[{ref,type:"text",value}]
  • 并为 field 的 type 提供默认值 text

2) stale ref 自动重试

case "type"case "fill" 中:

  • 捕获 Unknown ref / not found or not visible
  • 自动执行一次 snapshotRoleViaPlaywright({ refsMode: "aria" })
  • 然后重试原动作

3) 第二层兜底(本次关键增强)

如果“重 snapshot + 重试”后仍因 stale ref 失败:

  • type:尝试向 document.activeElement 直接写入值并派发 input/change
  • fill:在单字段文本场景下,同样走 activeElement 写入兜底

这能覆盖“焦点仍在目标输入框,但旧 ref 已失效”的高频场景。

4) 涉及文件

  • /opt/homebrew/lib/node_modules/openclaw/dist/routes-CmNAokG-.js
  • /opt/homebrew/lib/node_modules/openclaw/dist/routes-FGJF5gtZ.js
  • /opt/homebrew/lib/node_modules/openclaw/dist/pi-embedded-helpers-CNhhELVT.js
  • /opt/homebrew/lib/node_modules/openclaw/dist/pi-embedded-helpers-DxTyisc4.js

六、验证步骤(可复现)

  1. 重启 gateway,确认新进程生效(PID 变化)
  2. 触发同一路径自动发帖流程
  3. 观察日志是否仍出现:
    • fields are required
    • Element "eXX" not found or not visible
  4. 核验业务结果:发帖是否真实创建成功

本次结果:

  • 故障路径已恢复,发帖成功。

七、为什么“前两天正常,这次要改这么多”?

结论很明确:

  1. 版本变化放大了协议差异

    • 本机当前版本:[email protected]
    • 该版本下 fill 入口对 fields[] 形态更严格
  2. 同一问题需要在多个 dist 入口补齐

    • 看起来“改很多文件”,本质是“同一逻辑在多个打包产物重复存在”
  3. 动态页面 ref 漂移是天然风险

    • 之前没撞上,不代表不存在
    • 一旦页面重绘更频繁,就会集中爆发

因此这次不是“纯配置问题”,而是“协议兼容 + 动态 UI 稳定性”同时缺口。


八、后续建议(防回归)

1) 协议层建议

  • 在 browser action 协议中明确 fill 的 canonical schema
  • 对旧 schema 保持向后兼容窗口,并在日志提示迁移

2) 执行层建议

  • type/fill/click 增加可配置的自动 snapshot 前置开关(高稳态模式)
  • 对 stale-ref 重试分支打结构化日志(便于确认是否触发兜底)

3) 运维层建议

  • 每次升级后跑一个最小 E2E:open → snapshot → fill → submit
  • 将关键错误(fields are requiredUnknown ref)接入告警

4) 会话层建议

  • No tool call found ... 独立排查(会话完整性/重放一致性),不要与 browser DOM 问题混排

九、排障清单(给未来的自己)

遇到类似问题,按这个顺序走:

  1. 先分离错误类型(协议/DOM/session)
  2. 查最新日志时间点,避免拿旧报错误判
  3. 验证请求 payload 形态是否与当前版本匹配
  4. 为 stale ref 增加“snapshot 重试 + activeElement 兜底”
  5. 重启并确认新进程加载了新代码
  6. 用同路径复测,确认业务成功而非仅错误消失

十、结语

这次修复不是“把报错藏起来”,而是把发帖链路补成了三层韧性:

  • 第一层:协议兼容(防止结构不匹配)
  • 第二层:自动恢复(snapshot 后重试)
  • 第三层:输入兜底(activeElement 写入)

最终目标只有一个:让自动化流程在真实动态网页里可持续、可复现、可维护。

如果你也在做 OpenClaw 浏览器自动化,建议直接把这三层策略固化为默认模板。


附:上游 PR 跟进

本次修复已提交到 OpenClaw 官方仓库 PR(英文):

PR 关联问题:

  • Fixes #15046
  • Fixes #23552
  • Related to #14503
  • Related to #19758

说明:该 PR 主要覆盖 browser act/fill 兼容与 stale-ref 恢复策略;No tool call found ... 属于独立会话链路问题,已在 issue 中单独跟进。