Version
main
Platform
Subsystem
vfs
What steps will reproduce the bug?
import vfs from 'node:vfs';
const fs = vfs.create({ emitExperimentalWarning: false });
fs.mkdirSync('/target');
fs.symlinkSync('/target', '/link');
try {
fs.mkdirSync('/link/subdir', { recursive: true });
console.log('/target/subdir exists:', fs.existsSync('/target/subdir'));
} catch (err) {
console.log('threw:', err.code);
}
How often does it reproduce? Is there a required condition?
Always
What is the expected behavior? Why is that the expected behavior?
/target/subdir exists: true
Native recursive mkdir follows symlinked intermediate path components, so creating through /link/subdir should create subdir inside /target.
What do you see instead?
throws ENOTDIR
The recursive mkdir loop checks the symlink entry itself with entry.isDirectory() instead of resolving the intermediate symlink to its directory target.
Additional information
fs equivalent
import fs from 'node:fs';
import os from 'node:os';
import path from 'node:path';
const dir = fs.mkdtempSync(path.join(os.tmpdir(), 'mkdir-symlink-'));
const target = path.join(dir, 'target');
const link = path.join(dir, 'link');
fs.mkdirSync(target);
fs.symlinkSync(target, link);
try {
fs.mkdirSync(path.join(link, 'subdir'), { recursive: true });
console.log('target/subdir exists:', fs.existsSync(path.join(target, 'subdir')));
} catch (err) {
console.log('threw:', err.code);
}
Output
target/subdir exists: true
Version
main
Platform
Subsystem
vfs
What steps will reproduce the bug?
How often does it reproduce? Is there a required condition?
Always
What is the expected behavior? Why is that the expected behavior?
/target/subdir exists: trueNative recursive
mkdirfollows symlinked intermediate path components, so creating through/link/subdirshould createsubdirinside/target.What do you see instead?
throws
ENOTDIRThe recursive mkdir loop checks the symlink entry itself with
entry.isDirectory()instead of resolving the intermediate symlink to its directory target.Additional information
fs equivalent
Output
target/subdir exists: true