Skip to content

fix(serve): keep prompt-turn failure logs from degrading to [object Object] - #10732

Merged
yiliang114 merged 8 commits into
QwenLM:mainfrom
yiliang114:fix/serve-turn-failure-log-detail
Sep 2, 2026
Merged

fix(serve): keep prompt-turn failure logs from degrading to [object Object]#10732
yiliang114 merged 8 commits into
QwenLM:mainfrom
yiliang114:fix/serve-turn-failure-log-detail

Conversation

@yiliang114

@yiliang114 yiliang114 commented Sep 1, 2026

Copy link
Copy Markdown
Collaborator

What this PR does

When a prompt turn in qwen serve rejects with something that is not an Error instance — most notably the bare JSON-RPC error objects the bridge forwards ({ code, message, data }) — the daemon's prompt turn failed log line degraded to prompt turn failed: [object Object], erasing the failure cause. This PR routes that log line through the bridge's existing extractErrorMessage / extractErrorCode helpers (the same ones the sendPrompt: forward failed path already uses), so structured message, data.details, and error code survive into the daemon log. Error instances keep the [ErrorName] … prefix; note that extractErrorMessage prefers data.details over message for Errors too, so an Error carrying JSON-RPC data (ACP's RequestError) now logs the detail rather than the generic message — an intentional enrichment, not an unchanged path. Rejections that cannot be serialized (circular objects) fall back to util.inspect, which never throws.

Why it's needed

During a production incident investigation (#10710, teardown half in #10162) a killed prompt turn logged only prompt turn failed: [object Object], which made it impossible to tell from the daemon log why the turn died. The bridge already extracts these details elsewhere; the turn-failure log site simply bypassed that extraction.

Reviewer Test Plan

How to verify

New unit test packages/cli/src/serve/routes/session-turn-failure.test.ts covers describePromptTurnFailure:

  • Error instance → [BridgeChannelClosedError] agent channel closed mid-request (unchanged shape)
  • bare JSON-RPC object { code: -32603, message: 'Internal error' }[code -32603] Internal error
  • data.details / nested data.error.message preferred over the generic Internal error
  • plain objects with message, primitive rejections, and a guard that none of the structured shapes ever render [object Object]
$ npx vitest run src/serve/routes/session-turn-failure.test.ts
 Test Files  1 passed (1)
      Tests 10 passed (10)

Also ran npm run typecheck (clean), eslint on both touched files (clean), and the sibling suites that import session.js (session-prompt-terminals, session-telemetry: 14 passed).

Evidence (Before & After)

Production daemon log, before (v0.22.2, same code path):

[WARN] sessionId=<redacted> clientId=<redacted> promptId=<redacted> prompt turn failed: [object Object]

After (same rejection shapes):

prompt turn failed: [code -32603] Internal error
prompt turn failed: [code -32603] model provider rejected the request   (when data.details is present)
prompt turn failed: [BridgeChannelClosedError] agent channel closed mid-request (session <id>)   (Error rejections unchanged)

Tested on

OS Status
🍏 macOS ⚠️
🪟 Windows ⚠️
🐧 Linux

Environment (optional)

Unit tests only; no runtime needed.

Risk & Scope

Linked Issues

Part of the investigation in #10710 (does not close it); related to #10162.

中文说明

这个 PR 做了什么

qwen serve 里 prompt 轮次失败时,如果 rejection 不是 Error 实例——典型是 bridge 透传的裸 JSON-RPC 错误对象({ code, message, data })——daemon 日志会退化成 prompt turn failed: [object Object],故障原因直接丢失。本 PR 把这条日志改走 bridge 已有的 extractErrorMessage / extractErrorCodesendPrompt: forward failed 路径已经在用同一套提取逻辑),让结构化 message、data.details 和错误码都能进日志。Error 实例保留 [错误名] … 前缀;注意 extractErrorMessage 对 Error 同样优先取 data.details,因此携带 JSON-RPC data 的 Error(ACP 的 RequestError)现在会打出 detail 而非笼统 message —— 这是有意的信息增强,而非未改动的路径。无法序列化的 rejection(循环引用对象)回退到 util.inspect,不会抛异常。

为什么需要

在一次生产事故排查(#10710,拆 channel 的根因在 #10162)中,被杀的 prompt 轮次在 daemon 日志里只留下一行 prompt turn failed: [object Object],无法判断轮次为什么死。bridge 里本来就有这些细节的提取函数,只是这处日志没有用上。

审阅者测试计划

如何验证

新增单测 packages/cli/src/serve/routes/session-turn-failure.test.ts 覆盖 describePromptTurnFailure

  • Error 实例 → [BridgeChannelClosedError] agent channel closed mid-request(原格式不变)
  • 裸 JSON-RPC 对象 { code: -32603, message: 'Internal error' }[code -32603] Internal error
  • data.details / 嵌套 data.error.message 优先于笼统的 Internal error
  • message 的普通对象、原始值 rejection,并断言所有结构化形态都不会渲染出 [object Object]

10 个用例全部通过;npm run typecheck 干净;两个改动文件 eslint 干净;同样导入 session.js 的邻近测试套件(session-prompt-terminalssession-telemetry,14 个用例)全部通过。

前后证据

生产 daemon 日志,修复前(v0.22.2,同一代码路径):

[WARN] sessionId=<redacted> clientId=<redacted> promptId=<redacted> prompt turn failed: [object Object]

修复后(同样的 rejection 形态):

prompt turn failed: [code -32603] Internal error
prompt turn failed: [code -32603] model provider rejected the request   (有 data.details 时)
prompt turn failed: [BridgeChannelClosedError] agent channel closed mid-request (session <id>)   (Error rejection 不变)

测试环境

Linux ✅(仅单测,无需运行时)。

风险与范围

关联 Issue

#10710 排查的一部分(不关闭该 issue);与 #10162 相关。

…bject]

When a prompt turn rejects with a bare JSON-RPC error object (the shape
the bridge forwards for non-Error failures), the daemon logged
`prompt turn failed: [object Object]`, hiding the failure cause. Route
the log through the bridge's extractErrorMessage/extractErrorCode
helpers so the structured message and code survive.

Evidence: a production daemon incident where a killed turn logged only
`prompt turn failed: [object Object]` (see QwenLM#10710).

Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
@qwen-code-ci-bot

qwen-code-ci-bot commented Sep 1, 2026

Copy link
Copy Markdown
Collaborator

⚠️ Deferred approval withheld — 1 PR CI workflow run(s) on c72be0f did not finish green; see the updated table in the Stage 2 comment. Re-run @qwen-code /triage after fixes. finalize run

⚠️ 延迟审批已搁置 —— c72be0f 有 1 个 PR CI workflow 未以绿色完成,详见 Stage 2 评论中已更新的表格。修复后可重新运行 @qwen-code /triage查看 finalize 运行

@qwen-code-ci-bot

Copy link
Copy Markdown
Collaborator

Thanks for the PR!

Template looks good ✓

Problem: observed, not theoretical. The linked incident investigation (#10710) captured a production daemon log line prompt turn failed: [object Object], and I confirmed the lossy path exists on main: the turn-failure log site renders non-Error rejections with String(err), so any bare JSON-RPC error object forwarded by the bridge degrades to [object Object] and the failure cause is lost.

Direction: aligned — this is daemon-log observability, and the same class of fix shows up in the reference agent's changelog too (a fix for images rendering as "[object Object]", and one surfacing error detail instead of a degraded status line).

Size: not applicable — packages/cli/src/serve/routes/ is not a core module path; single package, 24 production lines + 68 test lines.

Approach: scope feels right. It reuses the bridge's existing extractErrorMessage/extractErrorCode helpers — the same extraction the sendPrompt: forward failed path already uses — so no new extraction logic is introduced, and Error rejections keep their existing shape. Explicitly scoping out the other String(err) log sites in the file is reasonable for a minimal fix.

Risk: no elevated risk signals — neither changed file matches the repo's revert-correlated high-risk paths.

Moving on to code review. 🔍

中文说明

感谢贡献!

模板完整 ✓

问题: 已观测到的真实问题,不是理论性加固。关联的事故排查(#10710)中,生产 daemon 日志出现了 prompt turn failed: [object Object];我也在 main 上确认了这条丢信息的代码路径确实存在:该轮次失败日志对非 Error rejection 使用 String(err) 渲染,bridge 透传的裸 JSON-RPC 错误对象会退化成 [object Object],故障原因直接丢失。

方向: 对齐——属于 daemon 日志可观测性改进;参考 agent 的 changelog 里也有同类修复(如图片渲染成 "[object Object]" 的修复、用错误详情替代退化状态行的修复)。

规模: 不适用——packages/cli/src/serve/routes/ 不属于核心模块路径;单包改动,24 行生产代码 + 68 行测试。

方案: 范围合理。复用了 bridge 已有的 extractErrorMessage/extractErrorCodesendPrompt: forward failed 路径用的就是同一套提取逻辑),没有引入新的提取逻辑;Error rejection 保持原格式。明确把文件里其他 String(err) 日志点划出范围,对最小修复来说是合理的。

风险: 无升级风险信号——两个改动文件均未命中本仓库与 revert 相关的高风险路径。

进入代码审查 🔍

Qwen Code · qwen3.8-max

Reviewed at c72be0f3e375bc911e4fbd6d596c892e8d46ea88 · re-run with @qwen-code /triage

@qwen-code-ci-bot

qwen-code-ci-bot commented Sep 1, 2026

Copy link
Copy Markdown
Collaborator

Code review

The approach matches what I'd have proposed independently: don't write new parsing — reuse the bridge's existing extractErrorMessage/extractErrorCode (the same extraction the sendPrompt: forward failed path already runs on the same rejection stream), wrap it in a small pure function at the log site, and keep the [Name] message shape for Error rejections.

I traced every test expectation against the helper implementations in bridge.ts — all seven match, including the data.details / nested data.error.message precedence. The structured log fields (sessionId, promptId, clientId) are untouched, and the diff carries no drive-by changes. License header, vitest import style, and the export-for-test pattern all match the sibling session-prompt-terminals / session-telemetry suites.

Two non-blocking notes:

  • The PR description says Error-instance lines are byte-identical to before. True for plain errors; an Error carrying structured .data (which the ACP SDK attaches on some failures) will now log the extracted detail instead of the bare message — same [Name] prefix, strictly more informative, so I read this as an improvement rather than a regression.
  • The same err instanceof Error ? err.message : String(err) pattern appears ~60 more times across the serve routes. The PR deliberately scopes to the one site proven lossy by the serve: reloading a session whose turn was killed mid-flight hides already-persisted assistant messages #10710 incident, which I think is the right call for a minimal fix — but a follow-up to sweep the rest would be worthwhile.

No blockers found.

Test evidence (from the PR's own CI via API — no PR code executed here)

At review time no check on the reviewed commit has failed; the primary unit suite and the daemon-side suites are still running, so this table reflects a mid-flight snapshot:

Final CI results for c72be0f (auto-updated by the triage finalize job after CI completed):

Check Conclusion
Test (ubuntu-latest, Node 22.x) ❌ failure
Classify PR ✅ success
Dependency CVE audit ✅ success
Desktop Shell (ubuntu-22.04) ✅ success
Desktop Shell (windows-2022) ✅ success
Integration Tests (no-AK, No Sandbox) ✅ success
macos-latest / Java 21 ✅ success
Real daemon E2E / Java 11 ✅ success
Secret scan (TruffleHog) ✅ success
Serve A/B (ubuntu-latest, Node 22.x) ✅ success
ubuntu-latest / Java 11 ✅ success
ubuntu-latest / Java 17 ✅ success
ubuntu-latest / Java 21 ✅ success
web-shell E2E Smoke (ubuntu-latest, Node 22.x) ✅ success
windows-latest / Java 21 ✅ success

One row per check name (latest run); skipped checks omitted; failures sort first. / 每个检查名一行(取最新一次运行),省略 skipped,失败项排在最前。

The macOS/Windows unit suites are skipped for this fork PR, so Linux is the OS coverage — consistent with what the author marked under "Tested on". The author's reported 7 passed for the new suite is their claim, not independently re-run here (unattended review never executes PR code); the in-progress Test (ubuntu-latest, Node 22.x) run is the authoritative signal and the finalize job will update the table above when CI settles.

Sandboxed verification would settle the one remaining gap: @qwen-code /verify — the unit tests pin describePromptTurnFailure's output for every shape, but not the end-to-end daemon log line under a real provider failure. This is a fork author, so that would be a sponsored run: a maintainer's @qwen-code /verify comment approves the head it was written against, the run carries a pre-execution risk screen and a full workspace wipe, and its report should be read with the same skepticism as the fork's own CI logs. The in-progress "Real daemon E2E" and "Serve A/B" jobs partially cover this path in the meantime.

Real-scenario (tmux) testing: N/A on this unattended run — and the surface here is a daemon log line, not the TUI; a maintainer can trigger the isolated @qwen-code /tmux job if they want live coverage.

中文说明

代码审查:方案与我独立设想的一致——不新写解析逻辑,直接复用 bridge 已有的 extractErrorMessage/extractErrorCodesendPrompt: forward failed 路径对同一条 rejection 流用的就是这套提取),在日志点包一个小而纯的函数,Error rejection 保持 [名字] message 原格式。我把 7 个测试断言逐条对照 bridge.ts 里的实现核验过,全部吻合(包括 data.details / 嵌套 data.error.message 的优先级)。结构化日志字段(sessionIdpromptIdclientId)未动,diff 无夹带改动;许可头、vitest 导入风格、为测试而导出的模式均与邻近的 session-prompt-terminals / session-telemetry 套件一致。

两条非阻塞备注:一是 PR 描述称 Error 实例的日志行逐字节不变——对普通错误成立,但携带结构化 .dataError(ACP SDK 在某些失败上会附加)现在会记录提取出的详情而非裸 message,前缀格式不变、信息只多不少,我视为改进而非回归;二是同样的 String(err) 模式在 serve 路由里还有约 60 处,本 PR 刻意只改被 #10710 事故证明丢信息的那一处,对最小修复是合理的,但后续值得做一次统一清扫。未发现阻塞问题。

测试证据(来自该 PR 自身的 CI,通过 API 读取;本审查未执行任何 PR 代码):截至审查时刻,被审提交上无失败检查;主单测套件与 daemon 侧套件仍在运行,上表为中途快照。macOS/Windows 单测对该 fork PR 被跳过,覆盖操作系统为 Linux,与作者"仅在 Linux 测试"的标注一致。作者报告的"7 个用例通过"是其自述,未被独立复跑;以进行中的 Test (ubuntu-latest, Node 22.x) 为准,CI 结束后 finalize 任务会更新上方表格。

沙箱验证可补上最后一个缺口:@qwen-code /verify——单测锁定了 describePromptTurnFailure 对每种形态的输出,但未锁定真实 provider 失败下端到端的 daemon 日志行。由于作者是 fork,这将是受助运行:由 maintainer 发 @qwen-code /verify 评论批准对应提交,运行前有预执行风险筛查与完整工作区清理,其报告应与 fork 自身 CI 日志同样审慎看待。进行中的 "Real daemon E2E" 与 "Serve A/B" 任务在此期间部分覆盖该路径。

真实场景(tmux)测试:本次无人值守运行不适用;且本改动面是 daemon 日志行而非 TUI,如需实机覆盖可由 maintainer 触发隔离的 @qwen-code /tmux 任务。

Qwen Code · qwen3.8-max

Reviewed at c72be0f3e375bc911e4fbd6d596c892e8d46ea88 · re-run with @qwen-code /triage

@qwen-code-ci-bot

Copy link
Copy Markdown
Collaborator

Confidence: 4/5 — a small, reuse-first fix for a failure mode that cost real debuggability in a production incident; the only open items are the still-running unit suite and the end-to-end log line that unit tests can't pin.

Going back to my independent proposal for this problem — reuse the bridge's existing JSON-RPC error extraction at the log site rather than writing new parsing, keep the Error shape, test the rendering directly — this PR is exactly that, no more and no less. The problem is verified (the [object Object] line exists on main for any non-Error rejection, and #10710 shows it happening in the wild), the fix is 15 lines of production code that lean on helpers already proven on the same rejection stream, and the tests pin the exact rendered output for every rejection shape that matters.

The two reservations from the review are minor and non-blocking: the "byte-identical for Error rejections" claim has a benign exception (errors carrying structured .data now log richer detail), and the unit suite pins the describe function rather than the end-to-end daemon log line — the in-progress "Real daemon E2E" and "Serve A/B" jobs cover part of that, and a sponsored @qwen-code /verify run would close it if a maintainer wants proof before merge.

Verdict: approve. Two pull_request workflow runs are still in flight on the reviewed commit, so approval is deferred until CI lands green on c72be0f3e375bc911e4fbd6d596c892e8d46ea88 — the finalize job will post it then.

中文说明

回到我对这个问题的独立设想——在日志点复用 bridge 已有的 JSON-RPC 错误提取而不是新写解析、保持 Error 原格式、直接测试渲染结果——这个 PR 恰好就是这么做的,不多不少。问题已核实(main 上任何非 Error rejection 都会渲染出 [object Object]#10710 证明它在生产真实发生过);修复只有 15 行生产代码,且依赖的是同一条 rejection 流上已被验证过的提取函数;测试对每种要紧的 rejection 形态都锁定了确切的渲染输出。

审查中的两点保留意见均属轻微、非阻塞:"对 Error rejection 逐字节不变"的说法有一个良性例外(携带结构化 .data 的错误现在会记录更丰富的详情);单测锁定的是 describe 函数本身,而非端到端的 daemon 日志行——进行中的 "Real daemon E2E" 与 "Serve A/B" 部分覆盖了后者,如 maintainer 需要合并前的实证,可发起受助的 @qwen-code /verify 运行。

结论:通过。被审提交上还有两个 pull_request 工作流在跑,批准将推迟到 CI 在该提交上全绿后由 finalize 任务自动完成。

Qwen Code · qwen3.8-max

Reviewed at c72be0f3e375bc911e4fbd6d596c892e8d46ea88 · re-run with @qwen-code /triage

@qwen-code-ci-bot

qwen-code-ci-bot commented Sep 1, 2026

Copy link
Copy Markdown
Collaborator

🩺 serve daemon A/B

Built the PR base vs this PR head 7efa602, drove a fixed endpoint set against each, and diffed the JSON responses. Only fields that changed are shown.

No response changes against the PR base across 12 scenario(s).

Qwen Code · serve A/B

@qwen-code-ci-bot qwen-code-ci-bot left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Partially reviewed — gaps disclosed. Suggestions are inline.

Not reviewed: reverse audit — stopped before round 4 by the review time budget.

Test Plan (not a blocker): src/serve/routes/session-turn-failure.test.tsno such file or directory.

中文说明

仅完成部分审查,审查缺口已披露。 建议见行内评论。

未审查:反向审计——评审时间预算不足,未能开始第 4 轮。

Test Plan(非阻断):src/serve/routes/session-turn-failure.test.tsno such file or directory

— qwen3.8-max via Qwen Code /review (v0.22.3)

Comment thread packages/cli/src/serve/routes/session.ts
Comment thread packages/cli/src/serve/routes/session.ts Outdated
Comment thread packages/cli/src/serve/routes/session-turn-failure.test.ts
@qqqys

qqqys commented Sep 1, 2026

Copy link
Copy Markdown
Collaborator

Review + E2E report (head c72be0f3e3)

Verdict: no Critical findings. Single call site (session.ts prompt-turn rejection handler), helpers imported from the bridge package root (export * from './bridge.js' — verified), and the [ErrorName] message shape is preserved for Error instances (extractErrorMessage only swaps in richer data.details/data.error.message when the Error carries a JSON-RPC data payload — same behavior as the existing sendPrompt: forward failed path).

Live A/B on a real daemon (tmux, head bundle vs base, hermetic HOME + mock gateway)

I could reproduce the exact #10710 incident shape in this environment — the bridge forwards the turn rejection as a bare JSON-RPC object {code: -32603, message: 'Internal error', data: {details: 'Connection error.'}}:

Build Rejection daemon log line
base (daemon built from #10731 head, which lacks this fix) connection error (gateway down) prompt turn failed: [object Object] (reproduced twice)
this PR head connection error (gateway down) prompt turn failed: [code -32603] Connection error.
this PR head mock gateway HTTP 400 {"error":{"message":"upstream 429 rate limited"}} prompt turn failed: [code -32603] 400 upstream 429 rate limited

Zero [object Object] occurrences in the head daemon's log across both failure modes; the structured code and provider detail survive.

Unit + mutation at head

  • New suite session-turn-failure.test.ts: 7/7 pass (Error name/message, code extraction, data.details preference, nested data.error.message, plain-object message, no-[object Object] sweep, primitive rejection).
  • Mutation A/B: reverse-applying only the session.ts hunk makes all 7 fail (describePromptTurnFailure is not a function) — the suite is coupled to the change, not vacuously green.

CI note

The red Test (ubuntu-latest) lane is pre-existing on main, not caused by this PR: components/ChatEditor.test.tsx:425:4: ERROR: The symbol "language" has already been declared (the duplicate declaration that #10729 fixes). All 5468 executable tests pass; only that suite's esbuild transform fails. A rebase onto a fixed main should turn it green.

A stale merge left two `language` interface members and two destructured
defaults in ChatEditor.test.tsx, breaking esbuild transform
("The symbol language has already been declared") in CI.

Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
Patrol-Run: qwen-pr-conflict/jmtj0ojdzar
@qwen-code-ci-bot

Copy link
Copy Markdown
Collaborator

🖼️ web-shell visual preview

Rendered against a mock daemon (no real backend): the PR base vs this PR head 9c79a6a. Only screenshots that changed are shown (flows below, if any, are head-only) — refreshes on every push.

Screenshots · before / after

terminal-turn-error-copy-narrow-light before/after

Full-resolution recordings (.webm) are attached to the workflow run.

Qwen Code · web-shell visuals

@qwen-code-ci-bot qwen-code-ci-bot left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Partially reviewed — gaps disclosed.

3 Suggestion-level finding(s) this review confirmed are already reported on this PR and are not repeated:

  • R1-1 formatter private to the patched log line; six sibling sites still degrade to [object Object] — still standing, already reported (comment 3906856737)
  • R1-2 degenerate non-Error shapes ({ code } / { message: '' }) still produce uninformative output — still standing, already reported (comment 3906856743)
  • R1-3 Error branch pinned only for bare Errors; two mutants survive the 7 current tests — still standing, already reported (comment 3906856757)

Not reviewed: build-and-test — Integration Tests (CLI, No Sandbox) was skipped in CI and the qwen serve integration suite did not run locally.

Not explored to full depth (tool budget reached): "agent 6a": none — no checks were cut short at the tool ceiling..

Test Plan (not a blocker): src/serve/routes/session-turn-failure.test.tsno such file or directory; Tests 7 passed — this review observed 5527, 503 passed; 14 passed — this review observed 5527, 503 passed.

中文说明

仅完成部分审查,审查缺口已披露。

本轮确认的 3 条建议级发现已在 PR 上报告过,不再重复发布(列表见上方英文部分)。

未审查:build-and-test — Integration Tests (CLI, No Sandbox) was skipped in CI and the qwen serve integration suite did not run locally。

未探索到全部深度(达到工具调用预算):"agent 6a"none — no checks were cut short at the tool ceiling.

Test Plan(非阻断):src/serve/routes/session-turn-failure.test.tsno such file or directory; Tests 7 passed — this review observed 5527, 503 passed; 14 passed — this review observed 5527, 503 passed

— qwen3.8-max via Qwen Code /review (v0.22.3)

@yiliang114
yiliang114 enabled auto-merge September 2, 2026 02:04
yiliang114 and others added 6 commits September 2, 2026 10:04
…ut-20260902

Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
Serialize structured non-Error rejections when message extraction is empty or would degrade to the default object string, while preserving Error formatting and extracted details.

Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
The JSON.stringify fallback throws on circular rejections, and the catch then
kept the extracted detail — which for a plain object is String(err), i.e. the
[object Object] this function exists to eliminate. util.inspect never throws,
handles circular refs and getters, and removes the try/catch, so the
"never degrades" contract now holds for every object shape. Add the circular
case the existing guard test omitted.

@qwen-code-dev-bot qwen-code-dev-bot left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reviewed at head 662105a7.

  • describePromptTurnFailure is a contained logging fix: Errors keep the [name] message shape, JSON-RPC-shaped rejections surface data.details / nested provider error / code, and plain objects fall through to inspect (never throws on circular or non-serializable values) so the incident-relevant cause can no longer degrade to [object Object].
  • The old call site's information loss is exactly what the new tests enumerate — the matrix covers Error, bare object, code-only, empty-message, circular, and primitive rejections.
  • 3/3 threads resolved; CI has no failures (lanes still running); per the channel convention the call is on the review itself.

@yiliang114 yiliang114 left a comment

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Review findings (self-PR, cannot self-approve):

  • describePromptTurnFailure fixes the #10710 symptom at the right seam: Error rejections keep '[Name] message', bare JSON-RPC error objects forwarded by the bridge get their message/code extracted via the existing acp-bridge helpers instead of degrading to '[object Object]', and data.details / nested provider error text are surfaced.
  • The inspect fallback is the right choice over JSON.stringify — it never throws, so circular/non-serializable rejections stay readable instead of degrading again; it only kicks in when extractErrorMessage would render '[object Object]'.
  • Call site updated in the daemon-log rejection handler; structured fields (sessionId/promptId/clientId) unchanged.
  • Nine unit tests cover the extraction matrix (Error name, RequestError data details, code prefix fallback, bare JSON-RPC objects, nested provider text, plain-object message).

CI on this head is still running; no blocking issues found.

@chiga0 chiga0 left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reviewed head 662105a720daa292d4e7dbff3d030ba6f2e08710, round 1.

No blocking findings. Approval blockers: none.

Checked:

  • extractErrorMessage and extractErrorCode are exported from @qwen-code/acp-bridge via bridge.ts:1797,1845index.ts: export * from './bridge.js'.
  • The inspect fallback condition (detail === '' || detail === String(err)) correctly catches both degenerate non-Error shapes: for { code: -32603 }, String(err) is '[object Object]' so detail === String(err) fires and inspect produces '{ code: -32603 }'; for { message: '' }, detail === '' fires and inspect produces "{ message: '' }". Both shapes are in the "never degrades" test candidate list (line 66) and both assertions would fail if the reviewer's described output were the actual output.
  • All 10 tests are non-vacuous: each would fail if describePromptTurnFailure were removed or any branch were regressed.
  • No persisted format, auth/credential, or API compatibility concerns.

Existing reviews cross-check (freeze → diff):

R1-1 — CONFIRMED: The six sibling sites (create-sub-session.ts:1066, scheduled-tasks.ts:594, dispatch.ts:5802, etc.) do still degrade. The PR description explicitly scopes them out as follow-up work; that scoping is appropriate — this PR fixes the one confirmed incident log site.

R1-2 — REFUTED: The witness describePromptTurnFailure({ code: -32603 }) => "[code -32603] [object Object]" is incorrect. The inspect fallback at line 478 fires for this input (detail === String(err) is true when both equal '[object Object]'), yielding '[code -32603] { code: -32603 }'. Similarly, { message: '' } triggers detail === ''inspect"{ message: '' }", not an empty string. The PR's own "never degrades" test (line 66) includes both shapes and its assertions would fail under the claimed outputs — yet the PR reports 10/10 passing.

R1-3 — REFUTED: The PR contains 10 tests, not 7. The two cases the prior reviewer recommends adding already exist: 'extracts data details from Error rejections carrying JSON-RPC data' (test file line 19) and 'keeps the Error name prefix over a code prefix' (test file line 29). Both mutations the reviewer describes are already caught.

Not covered: No working tree available, so execution rungs not run locally. Windows/macOS behavior not exercised. Neither is a coverage gap for this change — the fix is pure string construction with no OS-dependent path.

Reviewed with AI assistance.

@yiliang114
yiliang114 added this pull request to the merge queue Sep 2, 2026
Merged via the queue into QwenLM:main with commit 2ab1a3c Sep 2, 2026
84 of 85 checks passed
@qwen-code-ci-bot

Copy link
Copy Markdown
Collaborator

Released in v0.23.0.

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.

5 participants