Repository navigation
[Bug] Desktop 0.2.1-rc.2: enabling the experimental "Developer tools" can crash the host after its inspector source closes — "inspector: Host source is closed" #10069
Replies: 3 comments
|
The chain holds at Confirmed as written. Teardown order is safe, as you said — and worth pinning in the thread: One correction to your fix 2. "Make On your fix 3. "Downgrade the uncaught exception to a failure of this plugin" is not available, and not by accident — the host's fail-loud path is deliberate, because a host that survives a fatal error by staying quiet is worse to diagnose than one that stops. So the burden falls entirely on the weaker rule: a callback whose lifetime you do not own must not throw. That is fix 1, and it is the whole fix. Turning your C into an A, cheaply. The silent Plugin-mountability: none. The observer is created inside the same plugin against Finally, the correction you already made is the most useful part of the report: distinguishing the three |
|
@argszero 感谢仔细核对 —— disposal 的方向和 fail-loud 的代码依据都帮我们把结论收紧了,这两条比我们原来的方案准。下面是复核后的两处收紧(我们自己另拉了一路核对,不是照单全收): 中文
EnglishThanks — the disposal direction and the code-backed fail-loud reading tightened our conclusions; both are better than our original suggestions. Two refinements after an independent review on our side (we did not take it on trust):
|
|
感谢主贴和复核。补一条新的现场证据:确认复核里说"本次因有日志可排除"的第二条关闭路径 现象与日志
Worker 为什么会 ECONNRESET
浏览器端 Inspector/Client 连接异常断开(页面重载、DevTools 重连)时,原始 socket 的 补充证据:worker 死后 host 是"已上膛"的同一实例上观察到的运行期状态:Worker 已死后 建议补丁(socket 层,与主贴的 disposal 修复互补)--- a/packages/experimental/inspector/src/worker/bridge/endpoint.ts
+++ b/packages/experimental/inspector/src/worker/bridge/endpoint.ts
@@
private handleUpgrade(request: IncomingMessage, socket: Duplex, head: Buffer): void {
+ // node:http detaches its own socket error listener before emitting 'upgrade'
+ // (lib/_http_server.js: socket.removeListener('error', socketOnError)). The
+ // rejection branches below answer with socket.end() and never attach a handler,
+ // and ws owns the socket only after a completed handshake, so an abrupt client
+ // reset currently kills the Worker thread. Retain the process here.
+ socket.on('error', () => {})
let url: URL回归测试思路:用 本地处置(打包版无法改 asar)桌面 profile 的 patch 层禁用两行后稳定:重启后 8 分钟以上无新崩溃日志,且 - id: experimental-inspector
name: "@deepseek-ai/dsh-experimental-inspector"
disabled: true
- id: session-inspector
name: "@deepseek-ai/dsh-experimental-session-inspector"
disabled: trueEnglish summaryI can confirm the second close path you flagged in the review is not hypothetical: two The Worker death is a raw-socket problem: Operational note: after the Worker dies the Host stays alive with a closed source and a live observer; Suggested one-line hardening at the top of private handleUpgrade(request: IncomingMessage, socket: Duplex, head: Buffer): void {
+ socket.on('error', () => {})
let url: URLRegression test: bind with Local workaround: disabling Note: the diff above was prepared against |
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Desktop 0.2.1-rc.2:开启实验性「开发者工具」后,inspector 源关闭会让 host 崩溃 —
inspector: Host source is closed摘要
设置 → 实验性插件 → 打开「开发者工具」(
@deepseek-ai/dsh-experimental-inspector-profile)之后,HostInspectorSource一旦被关闭(异常协议帧 / 异常 disposal),Cordis 树观察者没有被停掉,下一次树变化会在HostBridgePublisher.setState()抛出未捕获异常并终止 host。严重度:P1,不是 P0。触发需要先发生一次「source 被关闭」;正常 disposal 路径是逆序的(观察者先 dispose、transport 最后关),不会触发。
环境
desktop现象
%APPDATA%\@deepseek-ai\dsh-desktop\logs\crash-2026-10-17T20-07-55-901Z-host.log(phase: running)。另外两次没有生成对应的crash-*-host.log。崩溃日志(节选):
源码链
①
setState()在 closed 时throw,而不是丢弃②
close()把 publisher 标记为 closed③ Cordis 树的观察者没有和 source 生命周期绑定
④ 异常后续
setState的 throw 发生在微任务里,没有 catch ⇒ uncaught exception ⇒installFailLoud⇒exit(1)。触发条件(重要)
HostInspectorSource的port.on('message')catch 会直接this.close()(transport.ts的catch { this.close() },无日志)——本次崩溃最可能的路径;lib:1886-1896)同样会关 source、留下活观察者;本次因有日志可排除。两条路径之后,下一次 Cordis 树变化就撞上
setState的 throw。版本差异
packages/experimental/inspectorinspector-profiledsh-v0.2.0-rc.2(639ed01)dsh-v0.2.1-rc.2(687f282)即:旧缺陷 + 新入口。上游
master(687f282)这两段实现未变。期望
close()时释放publishCordisTree的订阅(observeCordisTree本来就返回 disposer)。注意两处缺口:startInspector的markRunning(lib:1886-1896)可能在观察者注册之前就关掉 source ⇒ 注册时要检查source.closed;port.on('close')只queries.disconnect(),不关 publisher/source ⇒ 要把 port close 也纳入释放。setState在 closed 时 return 会让观察者永久活着、持续跑全树snapshot()—— 那是永久成本,不是修复。installFailLoud的 latch / release / exit 是刻意的;可行的是在回调边界内兜底(也就是第 1 条)。更正说明
初版对外写的是「打开开关 3/3 稳定崩溃,P0」。两路独立复核后更正:
20:07:55,phase: running)含 inspector 栈;另外 3 份是phase: startup,根因是dsh-desktop-host的INACTIVE_EFFECT与connection缺webRuntime,与 inspector 无关。setState静默丢弃不是修复(会留下永久全树 snapshot 成本)⇒ 改为 disposal;「改全局 fail-loud」不可行,回调内兜底保留;「唯一非 teardown 调用者」的说法不成立(worker 意外退出是第二条)。相关
English summary
Symptom. After enabling the experimental "Developer tools" (
@deepseek-ai/dsh-experimental-inspector-profile) on Desktop 0.2.1-rc.2, the host can die withfatal uncaught exception: Error: inspector: Host source is closed(one crash log captured at20:07:55,phase: running; the user reports three occurrences in total).Root cause.
HostBridgePublisher.setState()throws when closed instead of dropping the update;publishCordisTree()keeps observing the Cordis tree without binding to the source lifecycle, so once the source is closed (e.g. the silentcatch { this.close() }on a bad worker frame) the next tree change throws in a microtask with no catch and terminates the host (installFailLoud→exit(1)). Normal disposal is safe because the observer is disposed first.Severity: P1, not P0. The switch arms the chain; a protocol-level anomaly is still required to close the source. The first version of this report claimed "3/3, P0" — that was corrected after independent review: only one of the four host crash logs contains the inspector stack, the other three are startup failures caused by missing
webRuntime.Version note. The throwing code is identical in
dsh-v0.2.0-rc.2; 0.2.1 only added theinspector-profileentry bundle (old defect, newly exposed). Upstreammasteris unchanged.Suggested fix. Stop observation on close, make
setStatedrop silently likepublish, and at minimum downgrade the uncaught exception to a failure of this plugin instead of terminating the host.All reactions