I recently ran into a baffling next build
failure on a server where I colocated MongoDB, Next.js, and FeatherJS:
EACCES: permission denied, scandir '/data/mongodb/diagnostic.data'
At first, this made no sense. My code simply imported time standard files from:
await import(`/data/${type}/${meet}-${year}.json`);
This had worked flawlessly on other systems for years. So why the sudden failure?
On the new server, I had installed MongoDB locally, and MongoDB had created this path:
/data/mongodb/diagnostic.data
That was the difference. On all my previous systems, /data/
didn't exist at all.
"If
/data
doesn't exist, does Node or Webpack fall back toprojectRoot/data
?"
No, not officially. Node.js never does this.
But Webpack (and therefore, Next.js) sometimes does something that looks like fallback, but is really its own path resolution logic:
“Hmm,
/data/foo.json
— I don’t know that module, and it’s not innode_modules
, and/data
doesn’t exist on the host machine...
But I see there's adata/
folder in the project. Let me try that.”
So Webpack resolves /data/foo.json
as projectRoot/data/foo.json
, and it just works — until you install something (like MongoDB) that creates a real /data
directory on the OS.
Once /data/
exists on the actual filesystem:
Webpack tries to scan /data/
as a real directory
It hits diagnostic.data/
, which is permission-protected
next build
crashes with EACCES: permission denied
Always treat /data/...
as off-limits unless you're intentionally targeting the root of the server. Use project-relative paths like this:
import path from "path";
import fs from "fs/promises";
const filePath = path.resolve(
process.cwd(),
"data",
type,
`${meet}-${year}.json`
);
const fileContent = await fs.readFile(filePath, "utf-8");
const times = JSON.parse(fileContent);
This guarantees correct behavior regardless of what folders exist on the host system.
If you're using /data/...
and it "works," it's likely only because:
There's no real /data/
directory on your OS
Webpack defaulted to looking inside your project folder
But this is fragile behavior — and as soon as something like MongoDB creates a real /data
, it breaks. Don't rely on this. Always resolve paths relative to your project.
💡 Note to self:
"Hmm,/data/foo.json
— I don’t know that module, and it’s not innode_modules
, and/data
doesn’t exist on the host machine...
But I see there’s adata/
folder in the project. Let me try that."— That’s the mental model for how Webpack made this seem like it "just worked."