Skip to content

fix: override yauzl to 3.3.1 to fix Electron postinstall hang on Node 24.16.0+#3584

Merged
Siri-Ray merged 1 commit into
nexu-io:mainfrom
jeremeioss:fix/electron-postinstall-node24
Jun 4, 2026
Merged

fix: override yauzl to 3.3.1 to fix Electron postinstall hang on Node 24.16.0+#3584
Siri-Ray merged 1 commit into
nexu-io:mainfrom
jeremeioss:fix/electron-postinstall-node24

Conversation

@jeremeioss

Copy link
Copy Markdown
Contributor

Discovered while testing linux appimage build as part of this closed issue
Reported in this comment

Why

Running pnpm tools-pack linux build --to appimage on Node ≥ 24.16.0 fails
with:

⨯ ENOENT: no such file or directory, rename '.../builder/linux-unpacked/electron'
  -> '.../builder/linux-unpacked/Open Design'

electron-builder tries to rename the extracted Electron binary, but it
doesn't exist because Electron's postinstall silently produced a broken
runtime: electron/dist/ contains only v8_context_snapshot.bin — no binary,
no locales/, no resources/. The postinstall script exits 0 with no error or
warning.

Root cause

Electron's install.js uses extract-zipyauzlfd-slicer to extract
the downloaded binary zip. fd-slicer@1.1.0 implements its own destroy() on
ReadStream, dating back to before Node 8 added a native Readable.destroy().
These two implementations collide with a stream-lifecycle change introduced in
Node 24.16.0 (nodejs/node#63487).

When zlib.createInflateRaw() applies backpressure during decompression, Node
24's stream internals interact with fd-slicer's broken destroy in a way that
prevents the Readable from ever resuming. The raw stream stops after exactly 3
read operations (196,608 / 204,997 bytes), and inflation stalls at 97% (694,688
/ 715,208 bytes). No error event, no close event, no rejection — a silent hang.

This was confirmed by testing each layer in isolation: fs.createReadStream
InflateRaw works fine; fd-slicer ReadStream → PassThrough works fine;
fd-slicer ReadStream → InflateRaw hangs. The issue is specific to custom
JavaScript Readables with async _read piped into zlib on Node ≥ 24.16.0.

Why a pnpm override

yauzl@3.3.1 ([thejoshwolfe/yauzl#170]) fixes this by dropping fd-slicer
entirely — it only depends on pend. However, extract-zip@2.0.1 (used by
Electron's installer) pins yauzl@^2.10.0 and has been unmaintained for 6 years
(max-mapper/extract-zip#154), so the fix cannot flow through normal dependency
resolution. A pnpm override is the same approach used by VS Code
(microsoft/vscode#318682) and other projects hitting the same issue.

What users will see

No visible UI change. Users building the packaged app on Node ≥ 24.16.0 will
find that pnpm tools-pack linux build (and the equivalent macOS/Windows
paths) now complete successfully instead of silently producing a broken Electron
runtime.

Surface area

  • UI — new page / dialog / panel / menu item / setting / empty state in apps/web or apps/desktop (including Electron menu bar)
  • Keyboard shortcut — new or changed
  • CLI / env var — new od subcommand or flag, new tools-dev / tools-pack / tools-pr flag, or new OD_* env var
  • API / contract — new /api/* endpoint, new SSE event, or changed shape in packages/contracts
  • Extension point — new entry under skills/, design-systems/, design-templates/, or craft/, or change to the skills protocol
  • i18n keys — added new translation keys (see TRANSLATIONS.md for the locale workflow)
  • New top-level dependency — adding any new entry to the root package.json (dependencies or devDependencies); workspace-package package.json files are out of scope. Include a paragraph on what we get vs. what bytes we ship (see CONTRIBUTING.md → Code style)
  • Default behavior change — changes what existing users experience without opting in (default model, default setting, file/SQLite schema, auto-network on startup, auto-install)
  • None — internal refactor, docs, tests, or translation update only

New top-level dependency note: This is not a new dependency — it is a pnpm
override that forces all transitive yauzl resolution to the fixed 3.3.1.
No new package enters the dependency tree; existing yauzl@2.10.0 instances
(from extract-zipyauzl) are replaced in-place.

Screenshots

Not applicable — no UI change.

Bug fix verification

The bug is a silent hang in a transitive dependency during postinstall, which
is not easily reproducible in a unit test. Verification was done by:

  1. Confirming electron/dist/ is empty (only v8_context_snapshot.bin) on
    Node 24.16.0 without the override.
  2. Applying the override, running pnpm install, and confirming electron/dist/
    now contains the full runtime (binary, locales/, resources/,
    libffmpeg.so, etc.).
  3. Running pnpm tools-pack linux build --to appimage end-to-end successfully.

Validation

pnpm install                        # apply override, verify Electron installs correctly
pnpm guard                          # no new .js/.mjs/.cjs outside allowlist
pnpm typecheck                      # no type errors

…Node 24.16.0+

fd-slicer's custom destroy() collides with Node 24.16.0's stream
lifecycle change, causing extract-zip to silently hang at 97% during
Electron binary extraction. yauzl 3.x drops fd-slicer entirely.
extract-zip is unmaintained and pins yauzl ^2.10.0, so the fix can
only flow through a pnpm override.

Refs: thejoshwolfe/yauzl#170, nodejs/node#63487
@jeremeioss

Copy link
Copy Markdown
Contributor Author

@lefarcen this is the PR discussed here

@lefarcen lefarcen added size/S PR changes 20-100 lines risk/high High risk: apps/desktop, daemon, auth, migration, workflows, package deps type/bugfix Bug fix labels Jun 3, 2026
@lefarcen lefarcen requested a review from nettee June 3, 2026 17:12
@lefarcen

lefarcen commented Jun 3, 2026

Copy link
Copy Markdown
Contributor

Hey @jeremeioss, that's the one — and the writeup is exceptional. The layer-by-layer isolation (fs → InflateRaw works, fd-slicer → PassThrough works, fd-slicer → InflateRaw hangs) plus the cites to nodejs/node#63487, yauzl#170, and the VS Code precedent make the yauzl@3.3.1 override choice cleanly justified. The note that extract-zip has been unmaintained for 6 years also closes off the obvious "why not upstream the fix" question.

Routed to @nettee from the review pool. Labeled size/S · risk/high · type/bugfixrisk/high because this is a root-dependency resolution change that affects Electron postinstall behavior, so worth a second pair of eyes before merge. CI is green and lines up with your verification notes.

@nettee nettee left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@jeremeioss I verified that this override stays aligned with the current dependency graph: in this lockfile it only replaces Electron's extract-zip -> yauzl path, removes fd-slicer from that install chain, and keeps the package metadata and lockfile changes consistent for the Node 24 postinstall fix. Thanks for tracking down a subtle transitive dependency failure and keeping the remediation tight.

🔁 Powered by Looper · runner=reviewer · agent=codex · An autonomous AI dev team for your GitHub repos.

@github-actions

github-actions Bot commented Jun 4, 2026

Copy link
Copy Markdown
Contributor

Visual regression review

Head: 467b7b1 · Base: f3ec496

13 changed · 4 unchanged · 0 missing baseline · 0 failed

Changed cases

Case Main PR Diff
visual-design-systems main pr diff
visual-home main pr diff
visual-home-catalog main pr diff
visual-home-context-picker main pr diff
visual-home-plugin-filter main pr diff
visual-integrations main pr diff
visual-integrations-use-everywhere main pr diff
visual-new-project-modal main pr diff
visual-plugins main pr diff
visual-projects main pr diff
visual-projects-kanban main pr diff
visual-tasks main pr diff
visual-topbar-execution-switcher main pr diff
Unchanged cases
Case Main PR Diff
visual-avatar-menu main pr diff
visual-plugin-details main pr diff
visual-settings-byok main pr diff
visual-settings-execution main pr diff

Visual diff is advisory only and does not block merging.

@Siri-Ray Siri-Ray added this pull request to the merge queue Jun 4, 2026
Merged via the queue into nexu-io:main with commit aea4042 Jun 4, 2026
16 checks passed
@open-design-bot

Copy link
Copy Markdown
Contributor

🎉 📡 You just leveled up to Giotto

Giotto card for @jeremeioss

📡 ✨ Sending steady signals.

🙌 Your contributions send a clear signal across the network: you care about making Open Design better.

💛 Thanks for helping Open Design move forward. Keep building in the open. 🚀


📊 Rank #198 among 198 contributors.

🔗 Share on X (English) · 分享到 X(中文)

@kokisanai

Copy link
Copy Markdown
Contributor

Hi @jeremeioss!

Your first Open Design PR has been merged! Huge thanks for jumping in and improving the project!

You contributed:

Merged PR: #3584 fix: override yauzl to 3.3.1 to fix Electron postinstall hang on Node 24.16.0+
#3584

You fixed a packaging/install reliability problem at the dependency layer, which is exactly the sort of low-visibility work that saves people from painful setup failures. That makes you a strong fit for other desktop and install-adjacent cleanup.

For your next contribution, we picked two issues that look like a good follow-up:

  1. macOS 15: Open Design icon appears oversized in Launchpad and Dock #1751 macOS 15: Open Design icon appears oversized in Launchpad and Dock
    macOS 15: Open Design icon appears oversized in Launchpad and Dock #1751

This stays in the desktop packaging/distribution surface and is a concrete user-facing fix with a clear reproduction area.

  1. Sync and display CLI-installed MCP and Skill for unified management #1838 Sync and display CLI-installed MCP and Skill for unified management
    Sync and display CLI-installed MCP and Skill for unified management #1838

This is another install/management-adjacent task that benefits from comfort around app packaging and local environment behavior.

If one of these looks interesting, feel free to comment /claim on the issue and we will help you get started!

Once your second PR gets merged, you will move into our Continuous Contributor tier. We are also starting to highlight repeat contributors more actively in the community, so this is a great time to keep going!

Thanks again for the first PR, and welcome to the Open Design contributor community!

The Open Design team

P.S. We hang out in Discord — come say hi: https://discord.gg/3C6EWXbdQQ
There's a #contributors channel where folks share what they're working on.

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

Labels

risk/high High risk: apps/desktop, daemon, auth, migration, workflows, package deps size/S PR changes 20-100 lines type/bugfix Bug fix

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants