Skip to content

fix(desktop): resolve plugin SDK namespaces at call time - #107644

Closed
LisandroNahuelH wants to merge 1 commit into
NousResearch:mainfrom
LisandroNahuelH:fix/desktop-sdk-runtime-lazy
Closed

LisandroNahuelH wants to merge 1 commit into
NousResearch:mainfrom
LisandroNahuelH:fix/desktop-sdk-runtime-lazy

Conversation

@LisandroNahuelH

Copy link
Copy Markdown
Contributor

What does this PR do?

Fixes every runtime (disk-door) desktop plugin failing to load after the recent bundle change:

[plugins] runtime load failed (<id>) TypeError: Cannot convert undefined or null to object (…/app.asar.unpacked/dist/assets/sdk-*.js:5)

Root cause: inside the built sdk chunk, src/sdk/runtime.ts's module section can evaluate BEFORE the section that assigns the ./index namespace binding it reads — the module cycle (sdk/indexcontrib/*contrib/runtime-loadersdk/runtime) is preserved as concatenated sections, and the namespace read is a hoisted var that is still undefined at that point. The module-level GLOBALS object then froze those undefined values, so the first shim built on plugin load died on Object.keys(undefined) — for every plugin, including a zero-import probe plugin (the error points at the app's own chunk, not plugin code).

The fix resolves the namespaces at CALL time (sdkGlobals() read by installPluginSdk() and the shim builder) instead of capturing them at module-eval time. Both call sites only run after boot, when every binding is assigned. Single file, no API change.

Transparency note: this is the same lazy-read direction as #107303 and is submitted at the author's request as a minimal corroborating variant (maintainers: prefer whichever candidate you pick — happy to close this one in favor of the canonical fix). Related issue: #107288.

Related Issue

Related: #107288 — same regression and same diagnosis (this intentionally does not claim uniqueness; see note above).

Type of Change

  • 🐛 Bug fix (non-breaking change that fixes an issue)

Changes Made

  • apps/desktop/src/sdk/runtime.ts: replace the module-level GLOBALS constant with a sdkGlobals() accessor called by installPluginSdk() and shimUrl(), so the SDK/React namespaces are resolved at call time (post-boot) rather than captured during chunk evaluation.

How to Test

Repro on base (any packaged build of current main):

  1. Drop any runtime plugin at $HERMES_HOME/desktop-plugins/<id>/plugin.js — an empty probe (export default { id: 'probe', register() {} }) is enough.
  2. It fails with the TypeError above; logs/desktop.log shows [plugins] runtime load failed (…) pointing at sdk-*.js:5.

Proof the fix works (packaged Windows build, release/win-unpacked, Electron 40.10.2, desktop 0.17.2 / core v0.21.1):

  1. Chunk-level probe (instrumented the built shim builder to log the namespace object per shim key, then invoked the import-map builder in real Electron): base build logs __HERMES_PLUGIN_SDK__ → undefined and throws on the first Object.keys; with this patch all four namespaces log object and the import map builds.
  2. App level (patched build swapped into release/win-unpacked): all runtime plugins load — no runtime load failed lines after boot — and the affected statusbar chips render.

Checklist

Code

Documentation & Housekeeping

  • I've updated relevant documentation — N/A (code comment in runtime.ts documents the cycle and the lazy-read requirement)
  • I've updated cli-config.yaml.example if I added/changed config keys — N/A
  • I've updated CONTRIBUTING.md or AGENTS.md if I changed architecture or workflows — N/A
  • I've considered cross-platform impact (Windows, macOS) — the fix is renderer-side and platform-agnostic; verified on Windows, the same lazy-read approach was independently verified on Linux in fix(desktop): resolve plugin SDK namespaces lazily so disk plugins load in production builds #107303's thread
  • I've updated tool descriptions/schemas if I changed tool behavior — N/A

Screenshots / Logs

Before (base build, instrumented probe):

Cg key= __HERMES_PLUGIN_SDK__ typeof= undefined
TypeError: Cannot convert undefined or null to object
    at Object.keys (<anonymous>)
    at Cg (…/sdk-*.js:5:26820) …

After (same probe, patched build):

Cg key= __HERMES_PLUGIN_SDK__ typeof= object
Cg key= __HERMES_REACT_JSX_DEV__ typeof= object
Cg key= __HERMES_REACT_JSX__ typeof= object
Cg key= __HERMES_REACT__ typeof= object
→ import map builds, plugins load, no `runtime load failed` lines after restart

Every runtime (disk-door) desktop plugin fails to load:

  [plugins] runtime load failed (<id>) TypeError: Cannot convert undefined
  or null to object (…/app.asar.unpacked/dist/assets/sdk-*.js:5)

An empty probe plugin fails identically, and the error points at the
app's own chunk — plugin content is irrelevant.

Root cause: inside the built `sdk` chunk, this module's section can
evaluate BEFORE the section that assigns the `./index` namespace binding
it reads (module cycle around sdk/index → contrib → runtime-loader →
sdk/runtime preserved as concatenated sections; the namespace read is a
hoisted `var` still `undefined` at that point). The module-level
`GLOBALS` object then froze those `undefined` values, and the first
shim built on plugin load died on `Object.keys(undefined)` — for every
plugin, on every launch.

Resolve the namespaces at CALL time (`sdkGlobals()` read by
`installPluginSdk()` and the shim builder) instead of capturing them at
module-eval time. Both call sites only run after boot, when every
binding is assigned. No API change.

Verified on a packaged Windows build (release/win-unpacked, Electron
40.10.2, desktop 0.17.2 / core v0.21.1): before, an instrumented shim
builder logs `__HERMES_PLUGIN_SDK__` as `undefined` and the TypeError
fires on first plugin load; after, all four namespaces log `object`, the
import map builds, and plugins load with no `runtime load failed` lines
and their statusbar chips rendering.

Related: issue #107288 (same regression, same diagnosis); the same
lazy-read shape is proposed in #107303 — submitted at the author's
request as a minimal corroborating variant; maintainers should prefer
whichever candidate they pick.
@alt-glitch alt-glitch added type/bug Something isn't working P1 High — major feature broken, no workaround comp/desktop Electron desktop app (apps/desktop/*) comp/plugins Plugin system and bundled plugins duplicate This issue or pull request already exists labels Sep 10, 2026
@alt-glitch

Copy link
Copy Markdown
Contributor

This was generated by AI during triage.

Duplicate of #107303 (earliest open fix, same lazy-namespace-resolution approach in apps/desktop/src/sdk/runtime.ts), per the author's own transparency note. Same cluster: #107603, #107518, #107309, #107338, all for #107288. Maintainer to pick one.

@kshitijk4poor

Copy link
Copy Markdown
Contributor

Closing as a duplicate of #107303 (@g3org3yo, merged as 6c3d4a4 on 2026-09-10), which lands the same fix — apps/desktop/src/sdk/runtime.ts resolves the plugin SDK namespaces at call time via pluginNamespaces() instead of a module-init GLOBALS snapshot. Current main already carries it, and this branch now conflicts on that block.

Thanks for the independent diagnosis — the issue was real and the approach matched what merged. Credit for the fix goes to the earliest submitter per repo policy; if a follow-up gap surfaces in production builds, please open a fresh PR against current main.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

comp/desktop Electron desktop app (apps/desktop/*) comp/plugins Plugin system and bundled plugins duplicate This issue or pull request already exists P1 High — major feature broken, no workaround type/bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants