Repository navigation
vfs: createVfsHandlers() does not implement writev(fd, buffers, position) #66532
Description
Version
v26.10.0
Platform
Microsoft Windows NT 10.0.19045.0 x64
Subsystem
vfs
What steps will reproduce the bug?
test.cjs:
const vfs = require('node:vfs')
const path = require('node:path')
const fs = require('node:fs')
const myVfs = vfs.create()
myVfs.mount() // Cause VFS to install its fs handler
const outputPath = path.resolve('test.txt') // File on the real filesystem, not VFS
console.log('outputPath:', outputPath)
const fd = fs.openSync(outputPath, 'w')
fs.writev(
fd,
[Buffer.from('hello'), Buffer.from('world')],
null,
(err, bytesWritten) => {
console.log(err, bytesWritten)
},
)Run command:
PS D:\code\node-vfs-writev-bug> node --experimental-vfs test.cjs
outputPath: D:\code\node-vfs-writev-bug\test.txt
node:fs:1270
const promise = h.writev(fd, buffers, position);
^
TypeError: h.writev is not a function
at Object.writev (node:fs:1270:23)
at Object.<anonymous> (D:\code\node-vfs-writev-bug\test.cjs:13:4)
at Module._compile (node:internal/modules/cjs/loader:1956:14)
at Object..js (node:internal/modules/cjs/loader:2096:10)
at Module.load (node:internal/modules/cjs/loader:1678:32)
at Module._load (node:internal/modules/cjs/loader:1470:12)
at wrapModuleLoad (node:internal/modules/cjs/loader:261:19)
at Module.executeUserEntryPoint [as runMain] (node:internal/modules/run_main:171:5)
at node:internal/main/run_main_module:33:47
Node.js v26.10.0
How often does it reproduce? Is there a required condition?
Reproduces 100% of the time when a VFS is mounted and fs.writev() is called.
What is the expected behavior? Why is that the expected behavior?
fs.writev() should write to test.txt successfully.
The VFS handler should implement writev(), consistent with the other filesystem handlers.
What do you see instead?
outputPath: D:\code\node-vfs-writev-bug\test.txt
node:fs:1270
const promise = h.writev(fd, buffers, position);
^
TypeError: h.writev is not a function
at Object.writev (node:fs:1270:23)
at Object.<anonymous> (D:\code\node-vfs-writev-bug\test.cjs:13:4)
at Module._compile (node:internal/modules/cjs/loader:1956:14)
at Object..js (node:internal/modules/cjs/loader:2096:10)
at Module.load (node:internal/modules/cjs/loader:1678:32)
at Module._load (node:internal/modules/cjs/loader:1470:12)
at wrapModuleLoad (node:internal/modules/cjs/loader:261:19)
at Module.executeUserEntryPoint [as runMain] (node:internal/modules/run_main:171:5)
at node:internal/main/run_main_module:33:47
Node.js v26.10.0
Additional information
The issue reproduces simply by mounting any VFS, even though the file being written is outside the VFS mount.
In Node.js v26.10.0, the VFS handler installed for node:fs provides an async write() handler and a synchronous writevSync() handler, but does not provide an async writev() handler. See:
node/lib/internal/vfs/setup.js
Line 359 in 9224b24
| function createVfsHandlers() { |
fs.writev() calls the installed VFS handler unconditionally when VFS handlers are present. See:
Lines 1268 to 1270 in 9224b24
| const h = vfsState.handlers; | |
| if (h !== null) { | |
| const promise = h.writev(fd, buffers, position); |
This also affects fs.createWriteStream() when its _writev() path is used. See:
node/lib/internal/fs/streams.js
Lines 475 to 476 in 9224b24
| function writevAll(chunks, size, pos, cb, retries = 0) { | |
| this[kFs].writev(this.fd, chunks, this.pos, (er, bytesWritten, buffers) => { |
This also affects SEA applications built with node --build-sea sea-config.json with useVfs: true, since enabling useVfs implicitly mounts a VFS at startup. As a result, fs.writev() fails even without explicitly mounting a VFS.
Upstream issue: #62328
Activity
Hati- commentedon Oct 5, 2026
Workaround
As a temporary workaround, the missing
writev()VFS handler can be added at runtime using--expose-internals.Typescript example:
Non-SEA
For a normal Node.js application, call the patch immediately after mounting a VFS and before using code that may call
fs.writev():SEA
For an SEA built with:
the SEA VFS is already mounted before the embedded JavaScript entrypoint starts. Therefore, the patch can be called directly at the beginning of the SEA entrypoint: