pnpm/pnpm · warning
Failed to read virtualStoreDir at "${virtualStoreDir}"
Error message
Failed to read virtualStoreDir at "${virtualStoreDir}" What it means
While pruning extraneous packages from node_modules/.pnpm (the virtual store), pnpm lists the virtual store directory with fs.readdir. If that fails with anything other than ENOENT (permissions, I/O errors, EMFILE), it logs this warning and returns an empty list, so pruning is silently skipped for this run and stale package directories survive.
Source
Thrown at pnpm11/installing/linking/modules-cleaner/src/prune.ts:209
}
}
return new Set(orphanDepPaths)
}
function getScopeFromPackageName (pkgName: string): string | undefined {
if (pkgName[0] === '@') {
return pkgName.substring(0, pkgName.indexOf('/'))
}
return undefined
}
async function readVirtualStoreDir (virtualStoreDir: string, lockfileDir: string): Promise<string[]> {
try {
return await fs.readdir(virtualStoreDir)
} catch (err: any) { // eslint-disable-line
if (err.code !== 'ENOENT') {
logger.warn({
error: err,
message: `Failed to read virtualStoreDir at "${virtualStoreDir}"`,
prefix: lockfileDir,
})
}
return []
}
}
async function tryRemovePkg (lockfileDir: string, virtualStoreDir: string, pkgDir: string): Promise<void> {
const pathToRemove = path.join(virtualStoreDir, pkgDir)
removalLogger.debug(pathToRemove)
try {
await rimraf(pathToRemove)
} catch (err: any) { // eslint-disable-line
logger.warn({
error: err,
message: `Failed to remove "${pathToRemove}"`,View on GitHub (pinned to 6261b7f388)
Solutions
- Check permissions and ownership of node_modules/.pnpm and fix them (chown -R $(whoami) node_modules), then re-run pnpm install.
- If node_modules is disposable, remove it entirely and reinstall — the virtual store is rebuilt.
- If the error was EMFILE or transient I/O, close fd-heavy processes (watchers, editors) and retry the install.
Example fix
# before: pnpm warns "Failed to read virtualStoreDir at .../node_modules/.pnpm" during prune sudo chown -R "$(id -un):$(id -gn)" node_modules pnpm install # after: virtual store readable, pruning proceeds
Defensive patterns
Strategy: try-catch
Validate before calling
import fs from 'node:fs'
import path from 'node:path'
// Before install, confirm the virtual store is a readable directory.
function virtualStoreReadable (lockfileDir: string): boolean {
const dir = path.join(lockfileDir, 'node_modules/.pnpm')
try {
return fs.statSync(dir).isDirectory()
} catch (err: any) {
return err.code === 'ENOENT' // absent is fine
}
} Try / catch
Follow the source shape: catch readdir errors, treat ENOENT as empty (normal fresh install), and downgrade all other codes to a warning plus empty result so the install proceeds without pruning: catch (err) { if (err.code !== 'ENOENT') log.warn(err); return [] } Prevention
- Never mix sudo and non-sudo pnpm installs in the same project directory.
- In Docker, ensure the node_modules volume is owned by the container user.
- Close fd-heavy watchers if you see EMFILE during installs.
When it happens
Trigger: fs.readdir(virtualStoreDir) throws a non-ENOENT error: EACCES/EPERM on node_modules/.pnpm, EIO from a failing disk, EMFILE under heavy fd pressure, or ENOTDIR when something replaced the .pnpm directory with a file.
Common situations: node_modules partially owned by root after mixing sudo and non-sudo installs; Docker volume permission mismatches; a stray file named .pnpm; failing disk; file-descriptor exhaustion from a watcher process.
Related errors
- PROJECT_INACCESSIBLE
- Failed to remove "${pathToRemove}"
- UNSAFE_CHANGESET_DIR
- UNEXPECTED_VIRTUAL_STORE
- CONFIG_CONFLICT_VIRTUAL_STORE_ONLY_WITH_NO_MODULES_DIR
AI-assisted analysis of pnpm/pnpm@6261b7f388 (2026-08-17).
Data as JSON: /api/errors/927d88f82f101c79.
Report an issue: GitHub.