EROFS: read-only file system on Vercel or AWS Lambda
The error in your function logs (the path changes)Error: EROFS: read-only file system, open '/var/task/data/posts.json'
errno: -30,
code: 'EROFS',
syscall: 'open'
Your code writes a file inside the deployed project. Serverless functions can't do that. Save the data to a database or object storage, or use /tmp for throwaway files only.
Why it happens
On your laptop your code can write anywhere in the project folder. Serverless functions run from a read-only copy of your code. Vercel's docs say functions have a read-only file system with a writable /tmp scratch space of up to 500 MB. On AWS Lambda, /tmp is configurable from 512 MB to 10,240 MB, and AWS describes it as temporary and unique to each execution environment.
So a JSON file used as a database, a log file, a cache folder, or uploads saved to ./uploads all fail here. Even writing to /tmp only works for throwaway files: another instance of your function will not see them, and they disappear when the instance does.
Fix it by hand
- Find the write. The log names the file. In your code, search for
writeFile,appendFile,mkdir,createWriteStream, and upload settings that save to disk (for example multer'sdiskStorageor adest: 'uploads/'option). - Decide what the file is. If it must still be there on the next request (user data, uploads, anything people expect to see again), it needs real storage. If it is a scratch file you create and use within one request,
/tmpis fine. - For data that must last, move it to a database (Postgres, MySQL, a key-value store) or to object storage (S3, Cloudflare R2, Vercel Blob, Supabase Storage). For uploads, send the file straight to object storage instead of to disk.
- For scratch files, write under the system temp folder and clean up:
import { tmpdir } from 'node:os'; import { join } from 'node:path'; const file = join(tmpdir(), 'export.csv'); // /tmp/export.csv on Linux - For logs, use
console.logorconsole.error. Your host collects stdout and stderr, so you don't need a log file. - Redeploy and call the route that failed.
Stop it happening again
- Treat the project folder as read-only at runtime. Only the build step writes files.
- Keep a rule in your agent's project rules file: "Never write files at runtime outside the temp folder. Use the database or object storage."
- If you really need a disk that persists, host that part on a server or container with an attached volume instead of serverless functions.
Broke After Deploy $9
Broke After Deploy finds code that writes files on a server that doesn't keep them, uploads saved to a local folder, and SQLite used as the database on serverless hosting, and shows you the line before you deploy.
- Checks your project for 37 known causes of "works locally, breaks in production" and runs your production build.
- Paste the error and it finds the cause in your code, then lists what will break next.
- Verdict first. Every finding shows the file and line, what it breaks, and the fix as a diff that is applied only with your OK.
Broke After Deploy: how it works, with examples · Install guide
Works with Claude Code, Claude.ai, Cursor, Codex and other agents that read SKILL.md files. No installs, no accounts, works offline. No-questions refund.