Replies: 4 comments
A concrete case study: one swallowed client-plugin failure cost 3 app restarts and ~2 hoursI reported the swallowing behaviour in the opening post. Here is a fully diagnosed example from a real third-party plugin ( What the user saw (every time): …and the whole app dropped into recovery mode, with no message anywhere: not in the app log, not in the host log, not in the diagnostics bundle's Why it was expensive: the plugin actually had six independent 0.1.7 incompatibilities (removed Naming the plugin helped; naming the reason would have helped much more. If the Loader logged the rejection it caught — Suggested minimal shape (happy to file as an issue if the repo enables them): {"eventName":"renderer.boot.failed",
"details":{"pluginIds":["dsh-ears"],"failureReason":"renderer-failed",
"pluginErrors":[{"id":"dsh-ears","name":"Error",
"message":"typert-loader: dsh-ears invocation \"dshEars/listRoutes\" result codec has no create() factory",
"at":"client.js:apply"}]}}Also worth considering: a plugin whose |
Second case of the same family: an
|
|
Correction to my previous comment (peer review caught a misread field). In the comment above I described this case as "an
So the "pending dependency" framing is withdrawn for this case: the contribution is registered and the feature still doesn't appear, which points at the rendering path rather than dependency resolution. Two related observations from the same review do still stand and are worth keeping in the discussion's theme ("contributions can vanish without a trace"):
Either way the diagnosis cost is real: a registered-but-invisible contribution produces no error, no log and no diagnostic entry — the same observability gap as the swallowed- |
|
Correction / withdrawal of the "pending dependency" framing in my earlier comment. The case I described (a New-Session control that never appeared) turned out to be neither a swallowed error nor an unsatisfied dependency: the control is gated by a user setting. With 通用设置 → "代码工作工具" (code-work tools: trajectory view, turn code diff, and Agent-preset switching in a new conversation) switched off, the picker is intentionally not rendered; turning it on makes it appear immediately. The plugin even receives the flag as a hook — So the contribution was registered, the dependency situation was irrelevant, and the observable outcome was a feature-flagged-off control. Withdrawing the case from this discussion's evidence base. That said, it sharpens exactly the point this thread is about — observability of absent client contributions:
Hence the ask is unchanged but now better motivated: for gated contributions, surface the reason where the user expects the feature ("preset switching is disabled — enable 代码工作工具"), and keep the general recommendation that client-side contribution failures carry an id + reason on the plugin diagnostic surface. Between "flag off", "dependency pending" and "apply() rejected", all three currently look like nothing happened. |
Uh oh!
There was an error while loading. Please reload this page.
What happened
A third-party client plugin (
dsh-ears@0.3.2) failed to boot on DSH0.1.7-rc.1(Desktop 2.0.14) and thedesktop dropped the whole app into recovery mode. The only message available anywhere was:
The
lifecycle-events/startup.jsonlinside the exported diagnostics bundle is more useful but still does notcarry the cause:
{"eventName":"renderer.boot.failed", "details":{"rendererStatus":"failed","failureReason":"renderer-failed", "pluginCount":1,"pluginIds":["dsh-ears"]}}The actual cause — found only by reading the plugin's source — was that the client contribution's
apply()rejected:because the plugin's generated Typert codecs no longer satisfy the new contract
(
typert-loader: dsh-ears invocation "dsh-ears#dshEars/listRoutes" result codec has no create() factory;requireStrictCodecnow demandsmode: "strict", a stringtypeSymbol, and acreate()factory).So the chain is: codec contract drift →
$mountrejects →apply()rejects → client Loader marks theplugin failed → renderer boot fails → recovery mode, and every layer between the cause and the user
discards the reason.
Why it matters
"did not provide an error message".
"this plugin's UI is unavailable". Users then have to switch to another profile to get back in.
Suggestions
apply()rejects, capture and log the rejection(name + message + stack) instead of reporting only
pluginIds. If the client Loader genuinelysees no error, log what it did observe (which module, which phase, what the promise settled with).
lifecycle-eventsis the right place — afailureDetailfield next to
failureReasonwould have made this a five-minute diagnosis.disable that plugin's UI/slot contributions while letting the rest of the renderer boot. The current
behaviour means one third-party plugin's contract drift locks the user out of the app.
Reproduced with DSH Desktop 2.0.14 / kernel
0.1.7-rc.1on Windows; the same plugin worked on the0.1.5-rc.2line. Happy to provide the diagnostics bundle or a minimal reproduction plugin if useful.All reactions