Repository navigation
fix(desktop): replace cpSync with manual recursive copy for Windows non-ASCII path compatibility - #60480
fix(desktop): replace cpSync with manual recursive copy for Windows non-ASCII path compatibility#60480liuhao1024 wants to merge 1 commit into
Conversation
|
Thanks for investigating the Windows packaging failure. This needs a re-scope onto current main before it can address the active build path. Problems
Suggested changes
Automated hermes-sweeper review. |
… paths Recursive fs.cpSync fails inside Node's native copy path when the source path contains non-ASCII characters (e.g. C:\Users\Pınar): Node 22 throws EIO/errno 5 and Node 24 fail-fasts with 0xC0000409 before any handler runs. Replace both recursive cpSync sites (the copyBuildRelease wholesale directory branch and the conpty prebuild dir) with copyDirByFile, a per-file walk built on copyFileSync that never enters the native recursive path. The regression test mocks recursive cpSync to throw the Node 22 EIO form on every platform, so staging is proven not to depend on it; it fails on main and passes with this fix. Fixes NousResearch#60447 Refs NousResearch#70779
0bda32f to
97d9828
Compare
|
Re-scoped onto the active
For context, #70779 (which bundles this EIO family) has since added a second reproduction on a Chinese-username Windows 11 system with two useful data points: on Node 24 recursive |
ehz0ah
left a comment
There was a problem hiding this comment.
Approval conclusion (formal approval unavailable without explicit repository access)
Reviewed exact head 97d9828bcfc87f19bece21f808768f871331ed3a. I found no blocking issue.
Motivation
The desktop native dependency staging path uses recursive cpSync for node-pty directories. On Windows, that operation fails when the source path contains non-ASCII characters. This blocks desktop build or packaging for affected users. The change keeps the staging contract and replaces only the failing directory-copy mechanism.
Approach
copyDirByFile walks known node-pty payload directories, creates matching destination directories, and copies each regular file with copyFileSync. stageNodePtyInto uses it for nested build/Release directories and prebuilds/<platform>-<arch>/conpty. The existing top-level native-file filters and destination cleanup remain unchanged.
The positive path now stages the same regular-file payload without recursive cpSync. Filesystem errors still propagate to the existing build or packaging caller. There is no new retry or failure-suppression path.
Changes
apps/desktop/scripts/stage-native-deps.mjsadds the focused directory walker and replaces the two recursivecpSynccalls that can reach the affected Windows paths.apps/desktop/scripts/stage-native-deps.test.mjsexpands the filesystem mock and adds a non-ASCII-path regression case that verifies nested directory and file copying.
Both active production entry points are covered: the desktop build script and target-specific packaging through before-pack.mjs. The pinned node-pty@1.1.0 payload contains regular files only in these directories. Its own installation code also copies the relevant Windows payload files individually.
Risk to main
The main residual risk is that the helper intentionally ignores symlinks and special directory entries. Recursive cpSync would copy symlinks, but the pinned payload has none, so this does not change the current staging result. Regular-file content and modes matched the prior implementation in direct probes. Error propagation, overwrite behavior, and possible partial output after a copy failure remain compatible with the previous path.
Validation covered the focused suite at the PR head with 31 passing tests, the same change composed onto current main with 31 passing tests, and a counterfactual run against the base implementation where the new regression test failed as expected. Exact-head required CI is green, including JS and TS checks. OS-specific CI was skipped, so I am not treating Windows behavior as runner-verified here. The Windows failure and per-file success are supported by the linked reproduction and direct code-path analysis.
Overall assessment
This is a proportionate fix for the reported P1 packaging failure. It changes the two affected copy sites, preserves current payload semantics, and adds a regression test that fails without the production change. No P0-P2 defect was verified in the exact-head diff.
English verdict: APPROVE at 97d9828bcfc87f19bece21f808768f871331ed3a. The focused tests pass, the regression test fails against the base implementation, current-main composition is clean, and no blocking finding was identified.
…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>
|
Fixed on main by #113919 ( |
|
Thanks for the confirmation and the landing link! Glad to see this reach main via #113919 — the widened scope (the |
What does this PR do?
Stages node-pty's native payloads without recursive
fs.cpSync, which crashes in Node's native copy path when the source path contains non-ASCII characters (e.g.C:\Users\Pınar\...on Windows). Two symptoms of the same root cause are reported: Node 22 throws a catchableEIO/errno 5, and Node 24 fail-fasts with0xC0000409insidefsBinding.cpSyncCopyDirbefore any handler runs. Per-filecopyFileSyncnever enters that native path, so both theconptyprebuild directory andbuild/Releasesubdirectories are now staged throughcopyDirByFile, a small recursive walk overcopyFileSync.This is a re-scope of the original patch onto the current build path: the
.cjsscript it patched was deleted on main; the active call sites are inapps/desktop/scripts/stage-native-deps.mjs. The earlier PowerShell-based retry loop is dropped entirely (single-file copies don't hit the bug, so no retry is needed — and the unguarded shell-out was a liability on non-Windows hosts).Related Issue
Fixes #60447
Refs #70779 (bundles this EIO family with the 8.3 short-path family; also carries a second reproduction on a Chinese-username system where the same per-file workaround was verified end-to-end, and the Node 24 fail-fast variant)
Type of Change
Changes Made
apps/desktop/scripts/stage-native-deps.mjscopyDirByFile(srcDir, destDir): recursive directory copy built on per-filecopyFileSync, with a comment documenting the Windows non-ASCII source-path crash (EIOon Node 22,0xC0000409on Node 24)copyBuildRelease: wholesale directory entries now go throughcopyDirByFileinstead ofcpSync(..., { recursive: true })stageNodePtyInto: theconptyprebuild directory (the reported crash site) now goes throughcopyDirByFilecpSynccalls are unchanged (they never enter the native recursive path)apps/desktop/scripts/stage-native-deps.test.mjsvi.mock('node:fs')simulates the Node 22EIO/errno 5 for anyrecursive: truecpSync(delegating everything else to the real module), so every platform exercises the failure mode.../Pınar/hermes-agent/...) with aconpty/payload, nestedbuild/Releasesubdirectory, and filter-bait files (.pdb,README.md); staging must complete with byte-identical payloads and filtering preserved — it fails on main and passes with this fixHow to Test
cd apps/desktop && npx vitest run --project electron scripts/stage-native-deps.test.mjsstage-native-deps.mjsto main makes the newnon-ASCII source pathtest fail with the simulatedEIO: Access is deniedfrom the conpty directory copy, matching the original report's stack (stageNodePtyInto→cpSyncofnode-pty/prebuilds/win32-x64/conpty).C:\Users\Pınar),npm run buildinapps/desktoppreviously failed instage-native-deps; bug: Installation/Build fails on Windows when user path contains non-ASCII/Unicode characters (EIO Access Denied & path distortion) #70779 reports the same per-file workaround verified end-to-end on a Chinese-username system.Checklist
Code
fix(scope):,feat(scope):, etc.)pytest tests/ -qand all tests pass (JS-only change; full vitest suite for the touched file passes — 31/31)Documentation & Housekeeping
docs/, docstrings) — or N/A (helper docstring documents the failure mode)cli-config.yaml.exampleif I added/changed config keys — or N/ACONTRIBUTING.mdorAGENTS.mdif I changed architecture or workflows — or N/A