pnpm/pnpm · error · PnpmError
PROJECT_INACCESSIBLE
PROJECT_INACCESSIBLE
Error message
Cannot access registered project "${absoluteTarget}": ${message} What it means
After resolving a project-registry entry's target (pnpm11/store/controller/src/storeController/projectRegistry.ts:90), fs.stat on the registered project directory failed with something other than ENOENT (which would clean up the stale entry). Errors like EACCES throw PROJECT_INACCESSIBLE because pruning based on unreadable projects could remove live data.
Source
Thrown at pnpm11/store/controller/src/storeController/projectRegistry.ts:90
)
}
const absoluteTarget = path.isAbsolute(target) ? target : path.resolve(path.dirname(linkPath), target)
// Check if project still exists
try {
await fs.stat(absoluteTarget)
projects.push(absoluteTarget)
} catch (err: unknown) {
// Only clean up if project directory no longer exists
if (util.types.isNativeError(err) && 'code' in err && err.code === 'ENOENT') {
await fs.unlink(linkPath)
globalInfo(`Removed stale project registry entry: ${absoluteTarget}`)
return
}
// Can't access project - throw error to prevent incorrect pruning
const message = util.types.isNativeError(err) ? err.message : String(err)
throw new PnpmError('PROJECT_INACCESSIBLE',
`Cannot access registered project "${absoluteTarget}": ${message}`,
{
hint: `To remove this project from the registry, delete the symlink at:\n ${linkPath}`,
}
)
}
}))
return projects
}
View on GitHub (pinned to 6261b7f388)
Solutions
- Restore readable access to the project dir named in the message: `chmod -R a+rX <absoluteTarget>` or fix the mount.
- If the project is genuinely gone, remove the registry symlink at the linkPath given in the hint and re-run prune.
- Ensure the user running prune can stat every registered project (same UID/permissions model).
Example fix
// before $ pnpm store prune # ERR_PNPM_PROJECT_INACCESSIBLE: Cannot access registered project "/srv/app" // after $ chmod -R a+rX /srv/app # or: rm <linkPath-from-hint> $ pnpm store prune
Defensive patterns
Strategy: validation
Validate before calling
import fs from 'node:fs'
import os from 'node:os'
import path from 'node:path'
// every registered project target must be statable by this user before prune
function registeredProjectsAccessible (projects: string[]): boolean {
return projects.every((dir) => {
try {
fs.statSync(dir)
return true
} catch (err: any) {
return err.code === 'ENOENT' // gone is fine (auto-cleanup); EACCES is not
}
})
} Try / catch
try {
await store.prune()
} catch (err) {
if ((err as NodeJS.ErrnoException).code === 'ERR_PNPM_PROJECT_INACCESSIBLE') {
// hint names the linkPath; restore access to the project dir or rm the symlink
throw err // do NOT auto-delete: that is exactly what the guard prevents
}
throw err
} Prevention
- Keep registered project directories readable by the account that runs prune.
- Unmount (rather than break) network volumes holding workspace projects before pruning.
- When a project is truly deleted, remove its registry entry explicitly rather than relying on prune cleanup.
When it happens
Trigger: `pnpm store prune` when a registered project directory exists but stat fails: permission denied on the project dir, an unreachable mount (stale NFS), or I/O errors - i.e. anything that is neither 'exists' nor 'gone'.
Common situations: Project directories owned by another user or root on shared machines; project on a network volume that is currently unmounted-but-erroring; restrictive ACLs created by backup tools.
Related errors
- PROJECT_REGISTRY_ENTRY_INACCESSIBLE
- Failed to read virtualStoreDir at "${virtualStoreDir}"
- UNSAFE_CHANGESET_DIR
- exhausted temp-path attempts for atomic CAS rewrite
- CAFS shard path {} exists but does not resolve to a director
AI-assisted analysis of pnpm/pnpm@6261b7f388 (2026-08-17).
Data as JSON: /api/errors/272bc3372f8f2203.
Report an issue: GitHub.