Skip to content

fix(desktop): stage native deps via per-file copies to survive non-ASCII Windows paths - #103458

Closed
Tulovecare wants to merge 1 commit into
NousResearch:mainfrom
Tulovecare:fix/desktop-native-deps-nonascii-copy
Closed

Tulovecare wants to merge 1 commit into
NousResearch:mainfrom
Tulovecare:fix/desktop-native-deps-nonascii-copy

Conversation

@Tulovecare

Copy link
Copy Markdown

PR: fix(desktop): stage native deps via per-file copies to survive non-ASCII Windows paths

Summary

fs.cpSync({ recursive: true }) crashes the Node process on Windows
(STATUS_STACK_BUFFER_OVERRUN, 0xC0000409, no output) when a path contains
non-ASCII characters. The desktop pack stages node-pty / get-windows native
payloads under apps/desktop/dist, which inherits the user-profile path
component — so Windows users whose username is non-ASCII (e.g. C:\Users\涂)
can never complete a local desktop build
; the pack dies silently mid-stage
(npm run pack fails with no error, Hermes.exe never gets produced).

This replaces the two recursive fs.cpSync call sites in
apps/desktop/scripts/stage-native-deps.mjs — whole build/Release dirs and a
conpty/ prebuild subdir — with a copyDirSyncSafe helper that walks the tree
using per-file copies, sidestepping the buggy path. Semantics are equivalent for
these whole-directory copies; file modes are unchanged (files are still copied
with cpSync).

Reference: nodejs/node#60447 (the
underlying Node crash).

Changes

  • apps/desktop/scripts/stage-native-deps.mjs
    • add copyDirSyncSafe(srcDir, destDir) (recursive copy via per-file cpSync)
    • copyBuildRelease(): nested dirs → copyDirSyncSafe
    • stageNodePtyInto(): conpty/ prebuild subdir → copyDirSyncSafe
  • apps/desktop/scripts/stage-native-deps.test.mjs
    • new regression test staging survives non-ASCII source paths (recursive-copy crash workaround): fixture paths deliberately contain CJK
      characters; asserts host build/Release, a nested build/Release/sub
      directory (.node + plain file), and a nested conpty/x64/ prebuild dir are
      all staged. Pre-fix on Windows the recursive cpSync hard-crashes the test
      process; post-fix it passes everywhere.

Test plan

  • cd apps/desktop && npx vitest run scripts/stage-native-deps.test.mjs
    • New test passes; no regressions in the suite.
    • Note: darwin staging ships the Swift helper executable… asserts POSIX
      0o755 on a helper and fails on a Windows host regardless of this change
      (Windows does not map exec bits) — pre-existing, unrelated.
  • Real-world proof: the packaged desktop app was built end-to-end on a
    Windows 11 host whose user profile contains CJK characters. Before this fix
    the pack crashed silently at stage-native-deps; after, it stages
    node-pty (win32-x64) and get-windows (win32) and packs cleanly.
  • CI expectation: green on linux/macos; on windows-latest the new test passes
    with the fix (and would have hard-crashed pre-fix thanks to its non-ASCII
    fixture paths).

Notes

  • The helper is deliberately a private function (no export/ABI change); it only
    swaps the copy mechanism at existing call sites.
  • A proper upstream resolution lives in Node itself; until the Node fix reaches
    the Node versions Hermes supports, this workaround keeps local desktop builds
    working for affected users. Happy to drop it once the engine floor includes a
    fixed Node.

…CII Windows paths

fs.cpSync({ recursive: true }) crashes the Node process on Windows
(STATUS_STACK_BUFFER_OVERRUN, 0xC0000409, no output) when a path
contains non-ASCII characters, e.g. a user profile like C:\Users\涂.
The desktop pack stages node-pty and get-windows native payloads under
apps/desktop/dist, whose path inherits the user-profile component, so
Windows users with non-ASCII usernames could never complete a local
desktop build - the pack died silently mid-stage.

Replace the two recursive cpSync call sites (whole build/Release dirs
and a conpty/ prebuild subdir) with a copyDirSyncSafe helper that walks
the tree with per-file copies, sidestepping the buggy path. Semantics
are equivalent for these whole-directory copies and file modes are
unchanged (files are still copied with cpSync).

Reference: nodejs/node#60447 (the crash). Regression covered by a
staging test whose fixture path is deliberately non-ASCII and which
asserts nested directories are copied through recursively.

Verified by packaging the desktop app on a Windows host whose user
profile contains CJK characters: previously crashed mid-stage, now
packs cleanly end-to-end.
@alt-glitch alt-glitch added type/bug Something isn't working P2 Medium — degraded but workaround exists comp/desktop Electron desktop app (apps/desktop/*) platform/windows Native Windows-specific behavior or breakage sweeper:risk-platform-windows Sweeper risk: may break or behave differently on native Windows duplicate This issue or pull request already exists labels Sep 5, 2026
@alt-glitch

Copy link
Copy Markdown

This was generated by AI during triage.

Duplicate of #60480 - same fix (replace recursive fs.cpSync in stage-native-deps.mjs with per-file copies to survive non-ASCII Windows paths, nodejs/node#60447). #61832 and #66687 are also open for the same crash; maintainers will pick one from that cluster.

@Tulovecare

Copy link
Copy Markdown
Author

Closing this PR — the fix has been applied locally; upstream issue #60447 tracks the same bug and PR #60480 covers it.

@Tulovecare Tulovecare closed this Sep 5, 2026
teknium1 added a commit that referenced this pull request Sep 17, 2026
…k .bak wipe

The salvaged commits drop the cpSync/rmSync imports, but stageGetWindowsInto
landed on main after the PR was opened and still called both, so the module
threw ReferenceError on every platform (7 vitest failures on the cherry-picked
head). Route its six sites through copyFileSync/removeDirSync so get-windows
staging survives the same non-ASCII profile paths as node-pty.

preserveRollbackBackup had the same rmSync no-op as cleanStaleAppOutDir: a
surviving .bak makes renameSync fail, so the previous working build gets wiped
instead of kept as rollback material. Same existsSync -> removeDirSync fallback.

Earlier fixes for the same crash: #60480 (@liuhao1024), #61832 (@danilofalcao),
#76211, #103458, #109273, #111590.
Co-authored-by: liuhao1024 <liuhao1024@users.noreply.github.com>
Co-authored-by: danilofalcao <danilofalcao@users.noreply.github.com>
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/*) duplicate This issue or pull request already exists P2 Medium — degraded but workaround exists platform/windows Native Windows-specific behavior or breakage sweeper:risk-platform-windows Sweeper risk: may break or behave differently on native Windows type/bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants