Problem
Inside a Windows AppContainer, node cannot resolve the real path of a file the process is allowed to open:
- The native real-path lookup is refused with error 5.
- The JavaScript fallback,
fs.realpathSync / fs.realpath, walks every folder from the drive root with lstat and is refused at lstat 'C:\Users'.
(Measured in our Windows testing, 27 and 28 September 2026. Microsoft does not document this behaviour.)
With no workaround in place, the walk was first refused one step earlier, at lstat 'C:\'. With a preload that answers the drive root, it gets past that and is refused at lstat 'C:\Users'.
The CJS and ESM loaders use the JavaScript walk to resolve the main script and every module (toRealPath in lib/internal/modules/helpers.js; lib/internal/modules/run_main.js:38-41 on v24.x) unless --preserve-symlinks-main / --preserve-symlinks are given. An AppContainer is normally granted the folders it needs, not their ancestors, so node fails before any user code runs.
Minimal reproduction
- Put
main.js in a folder under C:\Users\<user>\... and grant the AppContainer read access to that folder only.
- Inside the container, run
node main.js. Observed: EPERM on lstat 'C:\Users'.
- Inside the container, call
fs.realpathSync.native on the same path. Observed: error 5.
Expected behaviour
Resolving a path the process can open does not require read access to its ancestors, or it fails with a clear error that names the folder and the workaround.
Proposed fix
- node: in
fs.realpathSync / fs.realpath on Windows, when lstat of an ancestor fails with EPERM/EACCES, do not fail the whole resolution; for example, treat an unreadable ancestor as not a link. Node already special-cases the root (getRealpathRootLstatPath).
- libuv (
uv_fs_realpath, src/win/fs.c): we have not isolated whether error 5 comes from the CreateFileW open or from GetFinalPathNameByHandleW(VOLUME_NAME_DOS). We can run a probe if maintainers name the call they want checked.
Why it matters
Every node program run inside an AppContainer fails at startup unless it is launched with flags most users do not know about. Windows edge cases already shaped this code: v6.4.0 (#7899) restored the JavaScript walk, and fs.realpathSync.native was added in v9.2.0.
Problem
Inside a Windows AppContainer, node cannot resolve the real path of a file the process is allowed to open:
fs.realpathSync/fs.realpath, walks every folder from the drive root withlstatand is refused atlstat 'C:\Users'.(Measured in our Windows testing, 27 and 28 September 2026. Microsoft does not document this behaviour.)
With no workaround in place, the walk was first refused one step earlier, at
lstat 'C:\'. With a preload that answers the drive root, it gets past that and is refused atlstat 'C:\Users'.The CJS and ESM loaders use the JavaScript walk to resolve the main script and every module (
toRealPathinlib/internal/modules/helpers.js;lib/internal/modules/run_main.js:38-41on v24.x) unless--preserve-symlinks-main/--preserve-symlinksare given. An AppContainer is normally granted the folders it needs, not their ancestors, so node fails before any user code runs.Minimal reproduction
main.jsin a folder underC:\Users\<user>\...and grant the AppContainer read access to that folder only.node main.js. Observed: EPERM onlstat 'C:\Users'.fs.realpathSync.nativeon the same path. Observed: error 5.Expected behaviour
Resolving a path the process can open does not require read access to its ancestors, or it fails with a clear error that names the folder and the workaround.
Proposed fix
fs.realpathSync/fs.realpathon Windows, whenlstatof an ancestor fails with EPERM/EACCES, do not fail the whole resolution; for example, treat an unreadable ancestor as not a link. Node already special-cases the root (getRealpathRootLstatPath).uv_fs_realpath,src/win/fs.c): we have not isolated whether error 5 comes from theCreateFileWopen or fromGetFinalPathNameByHandleW(VOLUME_NAME_DOS). We can run a probe if maintainers name the call they want checked.Why it matters
Every node program run inside an AppContainer fails at startup unless it is launched with flags most users do not know about. Windows edge cases already shaped this code: v6.4.0 (#7899) restored the JavaScript walk, and
fs.realpathSync.nativewas added in v9.2.0.