Skip to content

fix(setup): 开放平台页面读取偶发 fetch failed 自动重试并透出真实网络错误 - #913

Merged
deepcoldy merged 1 commit into
masterfrom
fix/open-platform-fetch-retry
Aug 18, 2026
Merged

fix(setup): 开放平台页面读取偶发 fetch failed 自动重试并透出真实网络错误#913
deepcoldy merged 1 commit into
masterfrom
fix/open-platform-fetch-retry

Conversation

@deepcoldy

Copy link
Copy Markdown
Owner

改了什么、为什么

用户在 dashboard 改机器人头像时报错「✗ 改头像失败:读取开放平台页面失败: fetch failed」。

排查结论:宿主机到 open.feishu.cn 的偶发网络抖动会让 undici 把请求直接抛成一句 TypeError('fetch failed')。daemon 日志显示同链路的 VC 事件订阅检查过去几天也多次偶发同样报错,而前一天同链路改头像又成功过;当前复现窗口外用同款 Node(v22.21.1)连续 30 次直连全部成功,确认是瞬态故障。现有代码对 console 入口页 GET 只请求一次、失败即中断,且真实原因(ECONNRESET / EAI_AGAIN 等,藏在 err.cause)被 safeErrorMessage 丢弃,用户和排障方只能看到一句 "fetch failed"。

修复两点:

  • 幂等 GET/HEAD 瞬态重试MutableCookieJar.fetchRaw 对每一跳的 GET/HEAD 在识别为瞬态网络错误(按错误码白名单 + undici fetch failed 形态判定,主动 abort/timeout 不算)时小步退避重试(300ms/900ms,共 3 次)。POST 绝不重试——console POST 全是写操作(建版/发布/base_info 等),传输错误时服务端可能已 commit,重试等于重复提交(与既有「outcome unknown 不得重建」的 fail-closed 语义一致,有测试守护)。
  • 报错透出 cause 链safeErrorMessage 展开 err.cause(含 happy-eyeballs 的 AggregateError),报错形如 fetch failed: connect ETIMEDOUT 1.2.3.4:443;长 token 脱敏保持不变。open-platform-renamefailureFromError 复用之,改名/改头像 POST 阶段的网络错误同样受益。

影响面

改动集中在 src/setup/open-platform-automation.ts 的共用 HTTP 层(MutableCookieJar)+ src/services/open-platform-rename.ts 错误信息,波及所有走 console 自动化的路径:

  • dashboard 改名/改头像(本次报障入口)
  • botmux setup 开放平台自动配置、已有应用列表/凭证读取、onboarding
  • VC 事件订阅检查、飞书 Web session 校验
  • QR 登录轮询是 POST(qrlogin/init / qrlogin/polling),不受重试影响;登录后的 cross-login GET 跳转幂等,可安全重试

不涉及 CLI 适配器 / 后端 / 会话类型分支,纯 Node 网络层,Linux/macOS 行为一致。

测试验证

  • pnpm build 通过
  • pnpm vitest run test/setup-open-platform-automation.test.ts test/open-platform-rename.test.ts test/open-platform-avatar.test.ts test/setup-open-platform-outcome.test.ts — 82 passed;引用方 test/feishu-login-manager.test.ts test/setup-pickers.test.ts test/dashboard-bot-onboarding.test.ts — 78 passed
  • 新增用例:GET 抖一次自动重试成功;重试耗尽返回 network 且 message 含 ECONNRESET;POST 传输错误只请求一次立刻抛出;非网络错误不重试;safeErrorMessage cause 链展开(普通 cause / AggregateError / code 补全 / 长 token 脱敏)
  • pnpm switch:here && pnpm daemon:restart 部署 live,等待 dashboard 改头像实测确认

Made with Cursor

宿主机到 open.feishu.cn 的偶发网络抖动会让 undici 把请求抛成一句
TypeError('fetch failed'),一次失败就中断整条 console 自动化链路——
dashboard 改头像/改名、VC 事件订阅检查都实测偶发中招,且真实原因
(ECONNRESET / EAI_AGAIN 等)藏在 err.cause 里被丢弃,无法排障。

- MutableCookieJar.fetchRaw:幂等 GET/HEAD 每跳对瞬态网络错误小步退避
  重试(300ms/900ms,共 3 次);POST 全是 console 写操作,传输错误时
  结果未知,保持单次绝不重试
- safeErrorMessage:展开 err.cause 链(含 happy-eyeballs AggregateError),
  报错带上真实网络错误码,长 token 脱敏保持不变
- open-platform-rename failureFromError 复用 safeErrorMessage,改名/改
  头像的 POST 阶段网络错误同样透出 cause

Co-authored-by: Cursor <cursoragent@cursor.com>
@deepcoldy
deepcoldy merged commit 6cd034b into master Aug 18, 2026
6 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant