Skip to content

fix(desktop): pin Electron below the broken native extract-zip install - #47792

Merged
austinpickett merged 2 commits into
NousResearch:mainfrom
xxxigm:fix/desktop-electron-extract-zip-pin
Jun 17, 2026
Merged

fix(desktop): pin Electron below the broken native extract-zip install#47792
austinpickett merged 2 commits into
NousResearch:mainfrom
xxxigm:fix/desktop-electron-extract-zip-pin

Conversation

@xxxigm

@xxxigm xxxigm commented Jun 17, 2026

Copy link
Copy Markdown
Contributor

Summary

Reported on Discord (Fuji_Mino, Windows 11 x64, v0.16.0): the desktop install always fails at the "Building desktop app" stage. Electron's postinstall aborts with:

npm error Error: Cannot find native binding.
npm error [cause]: prebuild for this platform is not bundled
(and @electron-internal/extract-zip-win32-x64-msvc is intentionally not published)
ERR_DLOPEN_FAILED loading index.win32-x64-msvc.node

This is a Hermes dependency-drift bug, not just the reporter's machine. Electron changed its install mechanism mid patch-series:

Electron Downloader Unzip
40.9.340.10.2 @electron/get@^2 extract-zip@^2 (pure JS)
40.10.3 / 40.10.4 @electron/get@^5 @electron-internal/extract-zip@^1 (native napi)

apps/desktop/package.json declares electronVersion: 40.9.3 (the tested, JS-extract build) but pinned the dependency loosely as electron: ^40.9.3. So npm ci / npm install silently resolved 40.10.3 / 40.10.4 — onto the brand-new native extract-zip whose win32-x64 binding fails to dlopen on the reporter's host. The committed lockfile on main already carried electron@40.10.3, and the installer's mirror fallback can't help (it re-runs Electron's own install.js, which uses the same broken native module).

Fix (commit 1)

  • Pin electron to an exact 40.10.2 — the newest build before the native extract-zip switch — and align build.electronVersion to match (electron-builder needs electronVersion/electronDist to match the installed binary; the old ^40.9.3 vs 40.9.3 was already inconsistent).
  • Add a root yauzl: ^3.3.1 override so the (re-introduced) JS extract-zip path also works on Node ≥ 24.16 / ≥ 26.1, where the old yauzl hangs — the same workaround the wider Electron ecosystem adopted (electron/electron#51619). The installer bundles Node 22 but also accepts a user's own newer Node.
  • Regenerate package-lock.json: drops @electron-internal/extract-zip + @electron/get@5, restores @electron/get@2 + extract-zip@2 + yauzl@3.4.0. Diff is confined to the Electron subtree.

Why this layer / why not chase upstream

The native binding is published for win32-x64, so this is an upstream dlopen failure Hermes can't fix in JS. What Hermes controls is which Electron the installer pulls. Pinning to the validated, JS-extract build makes installs deterministic and sidesteps the native module entirely. The yauzl override keeps the JS path healthy on modern Node, so the downgrade doesn't regress anyone.

Test plan (commit 2)

  • scripts/run_tests.sh tests/test_desktop_electron_pin.py — 3 passed. Invariants (no hard-coded version): Electron dep is an exact pin, equals build.electronVersion, and the lockfile resolves to the same version so npm ci stays consistent.
  • Needs a Windows reviewer: fresh npm ci in repo root → cd apps/desktop && npm run pack completes (no ERR_DLOPEN_FAILED).

xxxigm added 2 commits June 17, 2026 17:20
The Windows desktop install fails at "Building desktop app": Electron's
postinstall aborts with `ERR_DLOPEN_FAILED loading
index.win32-x64-msvc.node` / "Cannot find native binding" from
`@electron-internal/extract-zip`.

Root cause is a dependency drift, not the user's machine. Electron changed
its install mechanism mid-patch-series:

  electron 40.9.3 .. 40.10.2  -> @electron/get@^2 + extract-zip@^2 (pure JS)
  electron 40.10.3 / 40.10.4  -> @electron/get@^5 + @electron-internal/extract-zip@^1 (native napi)

apps/desktop declares `electronVersion: 40.9.3` (the tested, JS-extract
build) but pinned the dependency as `electron: ^40.9.3`, so `npm ci`/`npm
install` silently resolved 40.10.3/40.10.4 — onto the brand-new native
extract-zip whose win32-x64 binding fails to dlopen on some Windows hosts.
The committed lockfile already carried 40.10.3, and the installer's mirror
fallback can't help (it re-runs Electron's own `install.js`, which uses the
same broken native module).

Fix:
- Pin `electron` to an exact `40.10.2` — the newest build before the native
  extract-zip switch — and align `build.electronVersion` to match (Electron
  Builder needs electronVersion/electronDist to match the installed binary).
- Add a root `yauzl: ^3.3.1` override so the (re-introduced) JS extract-zip
  path also works on Node >= 24.16 / >= 26.1, where the old yauzl hangs.
  This is the same workaround the wider Electron ecosystem adopted.
- Regenerate package-lock.json: drops @electron-internal/extract-zip and
  @electron/get@5, restores @electron/get@2 + extract-zip@2 + yauzl@3.4.0.
…tract

Guards against the dependency drift that broke the Windows desktop install:
the Electron dependency must be an exact version, must equal
build.electronVersion, and the lockfile must resolve to that same version so
`npm ci` installs exactly what electron-builder packages. Asserts the
relationships, not a specific version number.
@xxxigm
xxxigm requested a review from a team June 17, 2026 10:21
@alt-glitch alt-glitch added type/bug Something isn't working comp/tui Terminal UI (ui-tui/ + tui_gateway/) dependencies Pull requests that update a dependency file P2 Medium — degraded but workaround exists labels Jun 17, 2026
@austinpickett
austinpickett merged commit 33b1d14 into NousResearch:main Jun 17, 2026
35 checks passed
alt-glitch added a commit that referenced this pull request Jun 18, 2026
PR #47792 pinned Electron to an exact 40.10.2 and regenerated the root
package-lock.json (dropping @electron/get@5 + @electron-internal/extract-zip,
restoring @electron/get@2 + extract-zip@2 + yauzl), but did not refresh the
shared npmDepsHash in nix/lib.nix. The hash still described the previous
40.10.3 lockfile, so npmConfigHook fails on every Nix build with
"npmDepsHash is out of date" for hermes-tui / hermes-web / hermes-desktop.

Regenerate the single shared hash to match the current lockfile.

Verified with fetchNpmDeps (authoritative, not prefetch-npm-deps):
  nix build .#tui.npmDeps  -> builds clean
  nix build .#tui          -> Validating consistency -> Installing dependencies
                              -> Finished npmConfigHook (no hash error)
alt-glitch added a commit that referenced this pull request Jun 18, 2026
…#48457)

PR #47792 pinned Electron to an exact 40.10.2 and regenerated the root
package-lock.json (dropping @electron/get@5 + @electron-internal/extract-zip,
restoring @electron/get@2 + extract-zip@2 + yauzl), but did not refresh the
shared npmDepsHash in nix/lib.nix. The hash still described the previous
40.10.3 lockfile, so npmConfigHook fails on every Nix build with
"npmDepsHash is out of date" for hermes-tui / hermes-web / hermes-desktop.

Regenerate the single shared hash to match the current lockfile.

Verified with fetchNpmDeps (authoritative, not prefetch-npm-deps):
  nix build .#tui.npmDeps  -> builds clean
  nix build .#tui          -> Validating consistency -> Installing dependencies
                              -> Finished npmConfigHook (no hash error)
waefrebeorn pushed a commit to waefrebeorn/slermes that referenced this pull request Jul 2, 2026
NousResearch#47792)

* fix(desktop): pin Electron below the broken native extract-zip install

The Windows desktop install fails at "Building desktop app": Electron's
postinstall aborts with `ERR_DLOPEN_FAILED loading
index.win32-x64-msvc.node` / "Cannot find native binding" from
`@electron-internal/extract-zip`.

Root cause is a dependency drift, not the user's machine. Electron changed
its install mechanism mid-patch-series:

  electron 40.9.3 .. 40.10.2  -> @electron/get@^2 + extract-zip@^2 (pure JS)
  electron 40.10.3 / 40.10.4  -> @electron/get@^5 + @electron-internal/extract-zip@^1 (native napi)

apps/desktop declares `electronVersion: 40.9.3` (the tested, JS-extract
build) but pinned the dependency as `electron: ^40.9.3`, so `npm ci`/`npm
install` silently resolved 40.10.3/40.10.4 — onto the brand-new native
extract-zip whose win32-x64 binding fails to dlopen on some Windows hosts.
The committed lockfile already carried 40.10.3, and the installer's mirror
fallback can't help (it re-runs Electron's own `install.js`, which uses the
same broken native module).

Fix:
- Pin `electron` to an exact `40.10.2` — the newest build before the native
  extract-zip switch — and align `build.electronVersion` to match (Electron
  Builder needs electronVersion/electronDist to match the installed binary).
- Add a root `yauzl: ^3.3.1` override so the (re-introduced) JS extract-zip
  path also works on Node >= 24.16 / >= 26.1, where the old yauzl hangs.
  This is the same workaround the wider Electron ecosystem adopted.
- Regenerate package-lock.json: drops @electron-internal/extract-zip and
  @electron/get@5, restores @electron/get@2 + extract-zip@2 + yauzl@3.4.0.

* test(desktop): lock the Electron pin/version/lockfile consistency contract

Guards against the dependency drift that broke the Windows desktop install:
the Electron dependency must be an exact version, must equal
build.electronVersion, and the lockfile must resolve to that same version so
`npm ci` installs exactly what electron-builder packages. Asserts the
relationships, not a specific version number.
waefrebeorn pushed a commit to waefrebeorn/slermes that referenced this pull request Jul 2, 2026
…earch#47792) (NousResearch#48457)

PR NousResearch#47792 pinned Electron to an exact 40.10.2 and regenerated the root
package-lock.json (dropping @electron/get@5 + @electron-internal/extract-zip,
restoring @electron/get@2 + extract-zip@2 + yauzl), but did not refresh the
shared npmDepsHash in nix/lib.nix. The hash still described the previous
40.10.3 lockfile, so npmConfigHook fails on every Nix build with
"npmDepsHash is out of date" for hermes-tui / hermes-web / hermes-desktop.

Regenerate the single shared hash to match the current lockfile.

Verified with fetchNpmDeps (authoritative, not prefetch-npm-deps):
  nix build .#tui.npmDeps  -> builds clean
  nix build .#tui          -> Validating consistency -> Installing dependencies
                              -> Finished npmConfigHook (no hash error)
habarmc1223-sudo pushed a commit to habarmc1223-sudo/hermes-agent-fluxmem that referenced this pull request Jul 8, 2026
NousResearch#47792)

* fix(desktop): pin Electron below the broken native extract-zip install

The Windows desktop install fails at "Building desktop app": Electron's
postinstall aborts with `ERR_DLOPEN_FAILED loading
index.win32-x64-msvc.node` / "Cannot find native binding" from
`@electron-internal/extract-zip`.

Root cause is a dependency drift, not the user's machine. Electron changed
its install mechanism mid-patch-series:

  electron 40.9.3 .. 40.10.2  -> @electron/get@^2 + extract-zip@^2 (pure JS)
  electron 40.10.3 / 40.10.4  -> @electron/get@^5 + @electron-internal/extract-zip@^1 (native napi)

apps/desktop declares `electronVersion: 40.9.3` (the tested, JS-extract
build) but pinned the dependency as `electron: ^40.9.3`, so `npm ci`/`npm
install` silently resolved 40.10.3/40.10.4 — onto the brand-new native
extract-zip whose win32-x64 binding fails to dlopen on some Windows hosts.
The committed lockfile already carried 40.10.3, and the installer's mirror
fallback can't help (it re-runs Electron's own `install.js`, which uses the
same broken native module).

Fix:
- Pin `electron` to an exact `40.10.2` — the newest build before the native
  extract-zip switch — and align `build.electronVersion` to match (Electron
  Builder needs electronVersion/electronDist to match the installed binary).
- Add a root `yauzl: ^3.3.1` override so the (re-introduced) JS extract-zip
  path also works on Node >= 24.16 / >= 26.1, where the old yauzl hangs.
  This is the same workaround the wider Electron ecosystem adopted.
- Regenerate package-lock.json: drops @electron-internal/extract-zip and
  @electron/get@5, restores @electron/get@2 + extract-zip@2 + yauzl@3.4.0.

* test(desktop): lock the Electron pin/version/lockfile consistency contract

Guards against the dependency drift that broke the Windows desktop install:
the Electron dependency must be an exact version, must equal
build.electronVersion, and the lockfile must resolve to that same version so
`npm ci` installs exactly what electron-builder packages. Asserts the
relationships, not a specific version number.
habarmc1223-sudo pushed a commit to habarmc1223-sudo/hermes-agent-fluxmem that referenced this pull request Jul 8, 2026
…earch#47792) (NousResearch#48457)

PR NousResearch#47792 pinned Electron to an exact 40.10.2 and regenerated the root
package-lock.json (dropping @electron/get@5 + @electron-internal/extract-zip,
restoring @electron/get@2 + extract-zip@2 + yauzl), but did not refresh the
shared npmDepsHash in nix/lib.nix. The hash still described the previous
40.10.3 lockfile, so npmConfigHook fails on every Nix build with
"npmDepsHash is out of date" for hermes-tui / hermes-web / hermes-desktop.

Regenerate the single shared hash to match the current lockfile.

Verified with fetchNpmDeps (authoritative, not prefetch-npm-deps):
  nix build .#tui.npmDeps  -> builds clean
  nix build .#tui          -> Validating consistency -> Installing dependencies
                              -> Finished npmConfigHook (no hash error)
santhreal pushed a commit to santhreal/hermes-agent that referenced this pull request Jul 13, 2026
NousResearch#47792)

* fix(desktop): pin Electron below the broken native extract-zip install

The Windows desktop install fails at "Building desktop app": Electron's
postinstall aborts with `ERR_DLOPEN_FAILED loading
index.win32-x64-msvc.node` / "Cannot find native binding" from
`@electron-internal/extract-zip`.

Root cause is a dependency drift, not the user's machine. Electron changed
its install mechanism mid-patch-series:

  electron 40.9.3 .. 40.10.2  -> @electron/get@^2 + extract-zip@^2 (pure JS)
  electron 40.10.3 / 40.10.4  -> @electron/get@^5 + @electron-internal/extract-zip@^1 (native napi)

apps/desktop declares `electronVersion: 40.9.3` (the tested, JS-extract
build) but pinned the dependency as `electron: ^40.9.3`, so `npm ci`/`npm
install` silently resolved 40.10.3/40.10.4 — onto the brand-new native
extract-zip whose win32-x64 binding fails to dlopen on some Windows hosts.
The committed lockfile already carried 40.10.3, and the installer's mirror
fallback can't help (it re-runs Electron's own `install.js`, which uses the
same broken native module).

Fix:
- Pin `electron` to an exact `40.10.2` — the newest build before the native
  extract-zip switch — and align `build.electronVersion` to match (Electron
  Builder needs electronVersion/electronDist to match the installed binary).
- Add a root `yauzl: ^3.3.1` override so the (re-introduced) JS extract-zip
  path also works on Node >= 24.16 / >= 26.1, where the old yauzl hangs.
  This is the same workaround the wider Electron ecosystem adopted.
- Regenerate package-lock.json: drops @electron-internal/extract-zip and
  @electron/get@5, restores @electron/get@2 + extract-zip@2 + yauzl@3.4.0.

* test(desktop): lock the Electron pin/version/lockfile consistency contract

Guards against the dependency drift that broke the Windows desktop install:
the Electron dependency must be an exact version, must equal
build.electronVersion, and the lockfile must resolve to that same version so
`npm ci` installs exactly what electron-builder packages. Asserts the
relationships, not a specific version number.
santhreal pushed a commit to santhreal/hermes-agent that referenced this pull request Jul 13, 2026
…earch#47792) (NousResearch#48457)

PR NousResearch#47792 pinned Electron to an exact 40.10.2 and regenerated the root
package-lock.json (dropping @electron/get@5 + @electron-internal/extract-zip,
restoring @electron/get@2 + extract-zip@2 + yauzl), but did not refresh the
shared npmDepsHash in nix/lib.nix. The hash still described the previous
40.10.3 lockfile, so npmConfigHook fails on every Nix build with
"npmDepsHash is out of date" for hermes-tui / hermes-web / hermes-desktop.

Regenerate the single shared hash to match the current lockfile.

Verified with fetchNpmDeps (authoritative, not prefetch-npm-deps):
  nix build .#tui.npmDeps  -> builds clean
  nix build .#tui          -> Validating consistency -> Installing dependencies
                              -> Finished npmConfigHook (no hash error)
Gravezzz pushed a commit to Gravezzz/hermes-agent that referenced this pull request Jul 21, 2026
NousResearch#47792)

* fix(desktop): pin Electron below the broken native extract-zip install

The Windows desktop install fails at "Building desktop app": Electron's
postinstall aborts with `ERR_DLOPEN_FAILED loading
index.win32-x64-msvc.node` / "Cannot find native binding" from
`@electron-internal/extract-zip`.

Root cause is a dependency drift, not the user's machine. Electron changed
its install mechanism mid-patch-series:

  electron 40.9.3 .. 40.10.2  -> @electron/get@^2 + extract-zip@^2 (pure JS)
  electron 40.10.3 / 40.10.4  -> @electron/get@^5 + @electron-internal/extract-zip@^1 (native napi)

apps/desktop declares `electronVersion: 40.9.3` (the tested, JS-extract
build) but pinned the dependency as `electron: ^40.9.3`, so `npm ci`/`npm
install` silently resolved 40.10.3/40.10.4 — onto the brand-new native
extract-zip whose win32-x64 binding fails to dlopen on some Windows hosts.
The committed lockfile already carried 40.10.3, and the installer's mirror
fallback can't help (it re-runs Electron's own `install.js`, which uses the
same broken native module).

Fix:
- Pin `electron` to an exact `40.10.2` — the newest build before the native
  extract-zip switch — and align `build.electronVersion` to match (Electron
  Builder needs electronVersion/electronDist to match the installed binary).
- Add a root `yauzl: ^3.3.1` override so the (re-introduced) JS extract-zip
  path also works on Node >= 24.16 / >= 26.1, where the old yauzl hangs.
  This is the same workaround the wider Electron ecosystem adopted.
- Regenerate package-lock.json: drops @electron-internal/extract-zip and
  @electron/get@5, restores @electron/get@2 + extract-zip@2 + yauzl@3.4.0.

* test(desktop): lock the Electron pin/version/lockfile consistency contract

Guards against the dependency drift that broke the Windows desktop install:
the Electron dependency must be an exact version, must equal
build.electronVersion, and the lockfile must resolve to that same version so
`npm ci` installs exactly what electron-builder packages. Asserts the
relationships, not a specific version number.
Gravezzz pushed a commit to Gravezzz/hermes-agent that referenced this pull request Jul 21, 2026
…earch#47792) (NousResearch#48457)

PR NousResearch#47792 pinned Electron to an exact 40.10.2 and regenerated the root
package-lock.json (dropping @electron/get@5 + @electron-internal/extract-zip,
restoring @electron/get@2 + extract-zip@2 + yauzl), but did not refresh the
shared npmDepsHash in nix/lib.nix. The hash still described the previous
40.10.3 lockfile, so npmConfigHook fails on every Nix build with
"npmDepsHash is out of date" for hermes-tui / hermes-web / hermes-desktop.

Regenerate the single shared hash to match the current lockfile.

Verified with fetchNpmDeps (authoritative, not prefetch-npm-deps):
  nix build .#tui.npmDeps  -> builds clean
  nix build .#tui          -> Validating consistency -> Installing dependencies
                              -> Finished npmConfigHook (no hash error)
leewenjie pushed a commit to leewenjie/hermes-agent that referenced this pull request Aug 7, 2026
NousResearch#47792)

* fix(desktop): pin Electron below the broken native extract-zip install

The Windows desktop install fails at "Building desktop app": Electron's
postinstall aborts with `ERR_DLOPEN_FAILED loading
index.win32-x64-msvc.node` / "Cannot find native binding" from
`@electron-internal/extract-zip`.

Root cause is a dependency drift, not the user's machine. Electron changed
its install mechanism mid-patch-series:

  electron 40.9.3 .. 40.10.2  -> @electron/get@^2 + extract-zip@^2 (pure JS)
  electron 40.10.3 / 40.10.4  -> @electron/get@^5 + @electron-internal/extract-zip@^1 (native napi)

apps/desktop declares `electronVersion: 40.9.3` (the tested, JS-extract
build) but pinned the dependency as `electron: ^40.9.3`, so `npm ci`/`npm
install` silently resolved 40.10.3/40.10.4 — onto the brand-new native
extract-zip whose win32-x64 binding fails to dlopen on some Windows hosts.
The committed lockfile already carried 40.10.3, and the installer's mirror
fallback can't help (it re-runs Electron's own `install.js`, which uses the
same broken native module).

Fix:
- Pin `electron` to an exact `40.10.2` — the newest build before the native
  extract-zip switch — and align `build.electronVersion` to match (Electron
  Builder needs electronVersion/electronDist to match the installed binary).
- Add a root `yauzl: ^3.3.1` override so the (re-introduced) JS extract-zip
  path also works on Node >= 24.16 / >= 26.1, where the old yauzl hangs.
  This is the same workaround the wider Electron ecosystem adopted.
- Regenerate package-lock.json: drops @electron-internal/extract-zip and
  @electron/get@5, restores @electron/get@2 + extract-zip@2 + yauzl@3.4.0.

* test(desktop): lock the Electron pin/version/lockfile consistency contract

Guards against the dependency drift that broke the Windows desktop install:
the Electron dependency must be an exact version, must equal
build.electronVersion, and the lockfile must resolve to that same version so
`npm ci` installs exactly what electron-builder packages. Asserts the
relationships, not a specific version number.
leewenjie pushed a commit to leewenjie/hermes-agent that referenced this pull request Aug 7, 2026
…earch#47792) (NousResearch#48457)

PR NousResearch#47792 pinned Electron to an exact 40.10.2 and regenerated the root
package-lock.json (dropping @electron/get@5 + @electron-internal/extract-zip,
restoring @electron/get@2 + extract-zip@2 + yauzl), but did not refresh the
shared npmDepsHash in nix/lib.nix. The hash still described the previous
40.10.3 lockfile, so npmConfigHook fails on every Nix build with
"npmDepsHash is out of date" for hermes-tui / hermes-web / hermes-desktop.

Regenerate the single shared hash to match the current lockfile.

Verified with fetchNpmDeps (authoritative, not prefetch-npm-deps):
  nix build .#tui.npmDeps  -> builds clean
  nix build .#tui          -> Validating consistency -> Installing dependencies
                              -> Finished npmConfigHook (no hash error)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

comp/tui Terminal UI (ui-tui/ + tui_gateway/) dependencies Pull requests that update a dependency file P2 Medium — degraded but workaround exists type/bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants