I used Claude Code to investigate this issue. What could have taken a day of back-and-forth debugging was resolved in a focused session — pinpointing the root cause, testing fixes, and ruling out dead ends systematically.
The Problem
After a successful deployment on AWS Amplify, the app was returning HTTP 500 with no build failure, no warning — just a blank page. CloudWatch logs showed this:
ln: failed to create symbolic link '/tmp/app/node_modules/node_modules': Read-only file system
ln: failed to create symbolic link '/tmp/app/public/public': Read-only file system
ln: failed to create symbolic link '/tmp/app/.next/static/static': Read-only file system
ln: failed to create symbolic link '/tmp/app/.next/server/chunks/chunks': Read-only file system
INIT_REPORT Init Duration: 767.95 ms Phase: invoke Status: error Error Type: Runtime.ExitError
Deployment was marked successful. The app was dead on arrival.
Stack: Next.js · pnpm monorepo · AWS Amplify SSR
Context
This is a pnpm monorepo with two apps:
-
app-1— already deployed and working on Amplify -
app-2— newly added to the monorepo, deployed in the same commit
Both apps share the root node_modules via pnpm hoisting.
What We Tried (All Failed)
1. output: 'standalone' in next.config.mjs
The idea was to bundle all dependencies into .next/standalone to avoid symlink resolution issues at runtime.
// next.config.mjs
const nextConfig = {
output: 'standalone',
};
Same symlink errors in CloudWatch. Didn't help.
2. Scoped install in Amplify build spec
preBuild:
commands:
- pnpm install --filter app-1...
The intent was to install only app-1's dependency tree to avoid app-2's deps affecting the hoisting layout. Same error.
3. Removed node_modules from Amplify cache
cache:
paths:
- '.next/cache/**/*'
# removed: node_modules/**/*
Ruled out stale cached node_modules. Same error.
4. pnpm.overrides to force a single React version
"pnpm": {
"overrides": {
"react": "^19.0.0",
"react-dom": "^19.0.0"
}
}
This was an attempt to eliminate the version conflict at the root. Same symlink error on Amplify.
5. Redeployed the last known-working commit
Redeploying the commit before app-2 was added worked perfectly. This confirmed the issue was introduced entirely by app-2 being part of the monorepo — not an Amplify infrastructure issue.
At this point we also found similar reports on the Amplify GitHub repo (#3793, #4079) with identical log output. Those were intermittent platform-side issues. Ours was consistent and reproducible — which pointed back to our code.
The Twist: A Local Build Failure Along the Way
While trying pnpm.overrides, the local build started failing with:
Cannot read properties of null (reading 'useContext')
Cannot read properties of null (reading 'useRef')
Occurring during prerendering of /404 and /500.
Root cause: pnpm was hoisting react@19.2.3 at root but react-dom@18.3.1 at root (pulled in by a transitive dependency from app-2). Two incompatible React instances in the same node_modules — classic split brain.
Fix: After removing the overrides, regenerating pnpm-lock.yaml from scratch cleaned up the hoisting and resolved the local build. This was a separate issue from the Amplify problem but surfaced during the same investigation.
The Actual Root Cause
app-1 and app-2 had different versions of React and Next.js:
| app-1 | app-2 | |
|---|---|---|
next |
15.1.11 |
16.1.4 |
react |
^19.0.0 |
19.2.3 |
react-dom |
^19.0.0 |
19.2.3 |
The version mismatch in Next.js was enough for pnpm to create a conflicting node_modules layout across the two apps — which Amplify's Lambda runtime couldn't handle at bootstrap.
The fix: Downgraded app-2's Next.js from 16.1.4 to 15.1.11 and aligned React/react-dom versions to match app-1. Clean layout, no symlink failures, app running.
Why It Didn't Fail Locally or on Vercel
To rule out our own code, we deployed the same commit to Vercel — it worked fine. Ran it locally — worked fine. Only Amplify was breaking.
That's because Node.js and Vercel are both flexible with how they resolve modules at runtime. Amplify's Lambda compute is not — it expects a specific node_modules layout and breaks silently at the build level but loudly at runtime when that layout doesn't match. - According to Claude 😊
Key Takeaway
If you're running a pnpm monorepo on Amplify SSR and seeing Read-only file system symlink errors in CloudWatch with a successful build — check your dependency versions across all apps before debugging Amplify's infrastructure.
Keep React and Next.js versions consistent across all apps in the monorepo. pnpm's hoisting is sensitive to version conflicts, and Amplify's runtime is sensitive to pnpm's hoisting layout.
Added a comment on the related GitHub issue here: aws-amplify/amplify-hosting#4079
Top comments (1)
Why we changed app-2 and not app-1:
app-1 was already in production and using a library that had a hard compatibility requirement on its specific Next.js version. Upgrading app-1 would have broken that integration entirely. app-2 was newly added with no such constraints, so downgrading it to match app-1 was the safer and cleaner call.