Environment
Node.js v25.6.1
nitropack 2.13.2
macOS
Reproduction
https://stackblitz.com/github/maxmalysh/nitro-fs-lite-enotdir
Describe the bug
It's not possible to cache both /foo and /foo/bar when using fs or fs-lite as the storage driver:
nitro: {
storage: {
// Broken because of the bug described below
cache: { driver: 'fs-lite', base: '.cache/nitro' }
}
}
Caching /foo creates a file on disk. Then caching /foo/bar needs /foo to be a directory — fails with ENOTDIR.
This makes fs or fs-lite unusable for route caching whenever a route can be both a leaf and a prefix of another route (e.g. /en and /en/about, or /items/123 and /items/123/details).
Steps to reproduce:
- Open the StackBlitz reproduction (or clone https://github.com/maxmalysh/nitro-fs-lite-enotdir)
- Visit
/foo — payload is cached successfully
- Visit
/foo/bar — crashes with ENOTDIR
Expected: Both routes cache their payloads successfully.
Actual:
{
"error": "ENOTDIR: not a directory, open '.../.cache/nitro/foo/bar'",
"code": "ENOTDIR"
}
Note: unstorage's key-to-path mapping (: → /) is by design. The question is whether nitro should normalize/hash
keys for filesystem drivers, or document that fs/fs-lite are unsafe for route-based caching.
Additional context
Real-world impact:
Logs
ℹ Error: ENOTDIR: not a directory, open './.nitro/cache/foo/bar'
⁃ (ENOTDIR: not a directory, open '.nitro/cache/foo/bar':undefined:undefined)
⁃ (at Error: ENOTDIR: not a directory, open '.nitro/cache/foo/bar':undefined:undefined:undefined:undefined)
[CAUSE]
Error {
code: 'ENOTDIR',
errno: -20,
path: './.nitro/cache/foo/bar',
syscall: 'open',
message: "ENOTDIR: not a directory, open
'./.nitro/cache/foo/bar'",
stack: "ENOTDIR: not a directory, open './.nitro/cache/foo/bar'\n" +
"at Error: ENOTDIR: not a directory, open './.nitro/cache/foo/bar':undefined:undefined)",
}
Environment
Node.js v25.6.1
nitropack 2.13.2
macOS
Reproduction
https://stackblitz.com/github/maxmalysh/nitro-fs-lite-enotdir
Describe the bug
It's not possible to cache both
/fooand/foo/barwhen usingfsorfs-liteas the storage driver:Caching
/foocreates a file on disk. Then caching/foo/barneeds/footo be a directory — fails withENOTDIR.This makes
fsorfs-liteunusable for route caching whenever a route can be both a leaf and a prefix of another route (e.g./enand/en/about, or/items/123and/items/123/details).Steps to reproduce:
/foo— payload is cached successfully/foo/bar— crashes with ENOTDIRExpected: Both routes cache their payloads successfully.
Actual:
{ "error": "ENOTDIR: not a directory, open '.../.cache/nitro/foo/bar'", "code": "ENOTDIR" } Note: unstorage's key-to-path mapping (: → /) is by design. The question is whether nitro should normalize/hash keys for filesystem drivers, or document that fs/fs-lite are unsafe for route-based caching.Additional context
Real-world impact:
perf(nitro,schema): inline payload in HTML for cached routes + add
payloadExtraction: 'client'nuxt/nuxt#34410ENOTDIRwhen a route has optional subroutes:Nuxt 4.4.2 - Dev Server - Payload extraction fails if a route has an optional subroute nuxt/nuxt#34547.
fs-lite, but only fordevStorage:fix(nitro): use hash-based cache for dev payloads nuxt/nuxt#34569
storagewithfs-liteis still affected:fix(nitro): use hash-based cache for dev payloads nuxt/nuxt#34569 (comment)
Logs