You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Fail soft on client-module registration mismatch: validate at dsh plugin add + isolate single-module combo failures
#6202
A single third-party plugin with a client-bundle packaging defect (__ModuleLoader__.load({id}) not matching its npm package name) takes down the entire client plugin system — every plugin fails, the web UI shows a fatal "Failed to load plugins" screen, and the desktop shell's recovery ladder escalates to safe mode (all home-patch entries commented, profile bundles reduced to core). One plugin's bug should disable one plugin, not the whole app.
I hit this in production yesterday (see repro below). The buggy package was mine and I've already fixed and republished it — but the platform-side blast radius is what this post is about.
Repro
Publish / install a package that declares dsh.client.platform: web and exports ./client, whose client bundle registers under a different id:
// package.json{"name": "my-broken-plugin","exports": {"./client": "./lib/client.js"},"dsh": {"client": {"platform": "web"}}}// lib/client.js — WRONG id (not the package name)window.__ModuleLoader__.load({id: "some-other-name",factory: ... })
dsh plugin --profile web add my-broken-plugin # succeeds — no validation# restart DSH → whole client combo batch fails
Fatal chain on 0.1.5-rc.1:
@deepseek-ai/dsh-client-modules/lib/index.js — graph row id is the package name (graphRow(packageName, rev, meta); client bundle resolved via exports["./client"]).
All client plugins are concatenated into one combo URL (/plugins/??<pkg1>/client.js,<pkg2>/client.js,...&rev=..., see comboUrl()).
Browser runtime @deepseek-ai/dsh-client-modules/lib/client.jsarrive(row): after the shared bundle script executes it checks factories.has(row.id) and throwsclient-modules: bundle ... loaded without registering "<pkg>" via __ModuleLoader__.load.
The throw is wrapped by @deepseek-ai/cordis-plugin-loader/lib/index.jsupdateError() → failed to import loader entry <hash> (<pkg>): ..., and the frontend renders the fatal loader-status screen.
The desktop shell then misreads it as a config conflict and escalates (disable entries → comment whole home patch → safe mode).
Proposal 1 — validate at install time
dsh plugin add (CLI, @deepseek-ai/dsh plugin subcommand) already reads the candidate's package.json to discover dsh.client and exports["./client"]. At that moment it has both the package name and the client file on disk — one cheap static check closes the whole failure class:
Parse the client bundle for __ModuleLoader__.load({ id: "..." }) calls (it's a plain script; a regex/AST scan is enough).
If a registration id differs from the owning package name → refuse the install (or at least --force-gated warning), with a message naming the file, the offending id, and the expected one.
This turns a boot-time fatal into an install-time error message, exactly where the user can still act on it.
Proposal 2 — fail soft at runtime: one broken module disables one plugin
Today one unregistered id poisons the whole combo batch because arrive() throws for the batch transport. Two options, either helps:
Isolate the failure: when factories.has(id) is false after the combo loads, mark only that row failed (surface it in loader-status as "plugin X failed to load: registration mismatch"), let the rest of the batch materialize normally.
Skip at composition time (belt and braces): the host already owns initialBundleSnapshot(); a static scan of each client bundle at compose time could drop mismatching entries from the combo and log a host-side warning, so a bad package never even reaches the browser.
The invariant worth protecting: the app must always boot; a mispackaged third-party client is a per-plugin defect and should cost exactly one plugin.
Real-world case: codebuddy-first-bridge@1.1.7 (fixed in 1.1.8 — id now equals the package name; root cause was repackaging a standalone indicator into the main package without updating the registration id).
Happy to turn either proposal into a PR if the direction sounds right.
reacted with thumbs up emoji reacted with thumbs down emoji reacted with laugh emoji reacted with hooray emoji reacted with confused emoji reacted with heart emoji reacted with rocket emoji reacted with eyes emoji
Uh oh!
There was an error while loading. Please reload this page.
Summary
A single third-party plugin with a client-bundle packaging defect (
__ModuleLoader__.load({id})not matching its npm package name) takes down the entire client plugin system — every plugin fails, the web UI shows a fatal "Failed to load plugins" screen, and the desktop shell's recovery ladder escalates to safe mode (all home-patch entries commented, profile bundles reduced to core). One plugin's bug should disable one plugin, not the whole app.I hit this in production yesterday (see repro below). The buggy package was mine and I've already fixed and republished it — but the platform-side blast radius is what this post is about.
Repro
Publish / install a package that declares
dsh.client.platform: weband exports./client, whose client bundle registers under a different id:Fatal chain on 0.1.5-rc.1:
@deepseek-ai/dsh-client-modules/lib/index.js— graph row id is the package name (graphRow(packageName, rev, meta); client bundle resolved viaexports["./client"])./plugins/??<pkg1>/client.js,<pkg2>/client.js,...&rev=..., seecomboUrl()).@deepseek-ai/dsh-client-modules/lib/client.jsarrive(row): after the shared bundle script executes it checksfactories.has(row.id)and throwsclient-modules: bundle ... loaded without registering "<pkg>" via __ModuleLoader__.load.@deepseek-ai/cordis-plugin-loader/lib/index.jsupdateError()→failed to import loader entry <hash> (<pkg>): ..., and the frontend renders the fatal loader-status screen.Proposal 1 — validate at install time
dsh plugin add(CLI,@deepseek-ai/dshplugin subcommand) already reads the candidate'spackage.jsonto discoverdsh.clientandexports["./client"]. At that moment it has both the package name and the client file on disk — one cheap static check closes the whole failure class:__ModuleLoader__.load({ id: "..." })calls (it's a plain script; a regex/AST scan is enough).--force-gated warning), with a message naming the file, the offending id, and the expected one.This turns a boot-time fatal into an install-time error message, exactly where the user can still act on it.
Proposal 2 — fail soft at runtime: one broken module disables one plugin
Today one unregistered id poisons the whole combo batch because
arrive()throws for the batch transport. Two options, either helps:factories.has(id)is false after the combo loads, mark only that row failed (surface it in loader-status as "plugin X failed to load: registration mismatch"), let the rest of the batch materialize normally.initialBundleSnapshot(); a static scan of each client bundle at compose time could drop mismatching entries from the combo and log a host-side warning, so a bad package never even reaches the browser.The invariant worth protecting: the app must always boot; a mispackaged third-party client is a per-plugin defect and should cost exactly one plugin.
Environment
codebuddy-first-bridge@1.1.7(fixed in 1.1.8 — id now equals the package name; root cause was repackaging a standalone indicator into the main package without updating the registration id).Happy to turn either proposal into a PR if the direction sounds right.
All reactions