You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
fs.openSync doesn't seem to have access to the vfs in sea mode. #302
What Node versions, OSs and CPU architectures are you building for?
node24-macos-arm64
Describe the Bug
When I make the fs calls below, the readFileSync call resolves correctly however the openSync call fails with: no such file or directory, open '/snapshot/grain/stdlib/array.gr'
If i'm not mistaken this is because the vfs-setup doesn't actually implement openSync and when the underlying MemoryProvider is initialized only the directories are loaded in and not the files. I looked into this a bit deeper I'm wondering if the actual problem I am running into is that installFsPatches in the vfs modules module_hooks doesn't seem to patch openSync at all.
Expected Behavior
The expected behaviour would t have it return a virtual file descriptor.
To Reproduce
I'm pretty sure you can just compare the result of openSync vs readFileSync on any file in the vfs.
I did a bit more research on this and there seems to be a few issues:
PKG
On the pkg side of things SeaProvider doesn't implement openSync which means operations that use it fallback to the underlying MemoryProvider implementation.
On it's own this doesn't seem like a big problem as falling back to the memory provider is the correct behaviour however during initialization only the directories are written here and not files themselves.
VFS
Diving a bit deeper then that there seem to be two problems on the vfs side, one the vfs never patches fs.openSync in installFsPatches which means that the vfs is completely ignored.
Beyond this issue
Beyond this issue if openSync was implemented and patched fully it would give us a file descriptor, however given the other fs functions that consume file descriptor are not handled it wouldn't be very useful as it would be invalid in any context it would be used in. Furthur there doesn't seem to be logic implemented in the vfs module yet to determine which vfs a file descriptor, making this issue seem rather non trivial to fix.
Your diagnosis is right on both counts — SEAProvider has no openSync, and installFsPatches never patches open* at all. But the last paragraph is where I'd push back, because it's what makes this look non-trivial when it isn't:
Further there doesn't seem to be logic implemented in the vfs module yet to determine which vfs a file descriptor [belongs to]
That layer already exists in @roberts_lando/vfs@0.3.3:
lib/fd.js — openVirtualFd / getVirtualFd / closeVirtualFd over a module-level map, with virtual fds allocated from 10000+ specifically so they can't collide with real ones. That's the routing.
lib/file_system.js already implements the whole family: openSync (:400), closeSync (:406), readSync (:415), fstatSync (:423), plus async open (:513), close (:531), read (:545), fstat (:556). createReadStream already goes through it (lib/streams.js:43 calls vfs.openSync).
So VirtualFileSystem is complete. Only two pieces are missing:
pkg — implement SEAProvider.openSync, returning a handle backed by the existing readFileSync / _fileCache. MemoryProvider already defines MemoryFileHandle, so this is mostly wiring. The directories-only population you spotted is fine once the provider stops falling through to super.
vfs — add open / openSync / read / readSync / close / closeSync / fstat / fstatSync (and fs.promises.open → FileHandle) to installFsPatches: route the path-taking one by mount point, the fd-taking ones via getVirtualFd(fd), and fall through to the real fs otherwise.
That's the fix I'd rather have than #304. Two reasons:
It works for unmodified third-party libraries. Nothing in node_modules is going to reach for process.pkg.vfs, but plenty of it calls fs.openSync.
It restores classic-mode parity — prelude/bootstrap.js has patched the full descriptor family for years, so this is a SEA regression rather than a missing feature.
I'll take both sides of this; I maintain the vfs fork too. Tracking the vfs half separately and will link it here.
On #304: I left a longer note on the PR. Short version — exposing the instance doesn't actually give you a working openSync, because virtualFs.openSync lands on MemoryProvider.openSync, which looks up the in-memory tree where only directories were ever created. It'll throw the same ENOENT you're seeing now.
Also seen: #305 (the realpathSync Windows path) and #301. Your toPlatformPath sketch in #305 looks right; I'll handle that one on the pkg side.
installFsPatches now patches openSync/open, readSync/read, closeSync/close and fstatSync/fstat, routing the path-taking ones by mount point and the fd-taking ones through the existing getVirtualFd table. Your repro passes:
Real-fs descriptors keep working alongside it — virtual fds start at 10000 precisely so they cannot shadow a real one.
fs.promises.open is deliberately left out for now: it has to return a real FileHandle, and VirtualFileHandle has no .fd/createReadStream/readLines/chmod. It still falls through to the real fs, so no behaviour change there. Shout if you need it.
Still to do on the pkg side: SEAProvider.openSync, so snapshot files resolve instead of falling through to MemoryProvider's directories-only tree. That is the other half of this issue and I will do it once the vfs release lands. #305 is on my list separately.
Activity
spotandjake commentedon Sep 15, 2026
I did a bit more research on this and there seems to be a few issues:
PKG
On the pkg side of things
SeaProviderdoesn't implementopenSyncwhich means operations that use it fallback to the underlyingMemoryProviderimplementation.On it's own this doesn't seem like a big problem as falling back to the memory provider is the correct behaviour however during initialization only the directories are written here and not files themselves.
VFS
Diving a bit deeper then that there seem to be two problems on the vfs side, one the vfs never patches
fs.openSyncininstallFsPatcheswhich means that the vfs is completely ignored.Beyond this issue
Beyond this issue if
openSyncwas implemented and patched fully it would give us a file descriptor, however given the otherfsfunctions that consume file descriptor are not handled it wouldn't be very useful as it would be invalid in any context it would be used in. Furthur there doesn't seem to be logic implemented in the vfs module yet to determine which vfs a file descriptor, making this issue seem rather non trivial to fix.robertsLando commentedon Sep 18, 2026
Your diagnosis is right on both counts —
SEAProviderhas noopenSync, andinstallFsPatchesnever patchesopen*at all. But the last paragraph is where I'd push back, because it's what makes this look non-trivial when it isn't:That layer already exists in
@roberts_lando/vfs@0.3.3:lib/fd.js—openVirtualFd/getVirtualFd/closeVirtualFdover a module-level map, with virtual fds allocated from 10000+ specifically so they can't collide with real ones. That's the routing.lib/file_system.jsalready implements the whole family:openSync(:400),closeSync(:406),readSync(:415),fstatSync(:423), plus asyncopen(:513),close(:531),read(:545),fstat(:556).createReadStreamalready goes through it (lib/streams.js:43callsvfs.openSync).So
VirtualFileSystemis complete. Only two pieces are missing:SEAProvider.openSync, returning a handle backed by the existingreadFileSync/_fileCache.MemoryProvideralready definesMemoryFileHandle, so this is mostly wiring. The directories-only population you spotted is fine once the provider stops falling through tosuper.open/openSync/read/readSync/close/closeSync/fstat/fstatSync(andfs.promises.open→FileHandle) toinstallFsPatches: route the path-taking one by mount point, the fd-taking ones viagetVirtualFd(fd), and fall through to the real fs otherwise.That's the fix I'd rather have than #304. Two reasons:
node_modulesis going to reach forprocess.pkg.vfs, but plenty of it callsfs.openSync.prelude/bootstrap.jshas patched the full descriptor family for years, so this is a SEA regression rather than a missing feature.I'll take both sides of this; I maintain the vfs fork too. Tracking the vfs half separately and will link it here.
On #304: I left a longer note on the PR. Short version — exposing the instance doesn't actually give you a working
openSync, becausevirtualFs.openSynclands onMemoryProvider.openSync, which looks up the in-memory tree where only directories were ever created. It'll throw the same ENOENT you're seeing now.Also seen: #305 (the
realpathSyncWindows path) and #301. YourtoPlatformPathsketch in #305 looks right; I'll handle that one on the pkg side.robertsLando commentedon Sep 18, 2026
The vfs half is up:
installFsPatchesnow patchesopenSync/open,readSync/read,closeSync/closeandfstatSync/fstat, routing the path-taking ones by mount point and the fd-taking ones through the existinggetVirtualFdtable. Your repro passes:Real-fs descriptors keep working alongside it — virtual fds start at 10000 precisely so they cannot shadow a real one.
fs.promises.openis deliberately left out for now: it has to return a realFileHandle, andVirtualFileHandlehas no.fd/createReadStream/readLines/chmod. It still falls through to the real fs, so no behaviour change there. Shout if you need it.Still to do on the pkg side:
SEAProvider.openSync, so snapshot files resolve instead of falling through toMemoryProvider's directories-only tree. That is the other half of this issue and I will do it once the vfs release lands. #305 is on my list separately.fix: patch the fd family (open/read/close/fstat) in installFsPatches (#…