How to Fix Next.js Broken Pipe on Google Cloud Run
Troubleshooting Next.js “Broken Pipe” on Google Cloud Run
As a Senior DevOps Engineer, encountering a “Broken Pipe” error with your Next.js application on Google Cloud Run can be frustrating. This guide will walk you through the common causes and solutions, focusing on the unique environment of Cloud Run.
1. The Root Cause: Why This Happens on Google Cloud Run
The “Broken Pipe” error (EPIPE) typically indicates that a process tried to write data to a pipe, but the reading end of the pipe was closed before the write operation could complete. In the context of a Next.js application on Google Cloud Run, this almost invariably points to one core issue: your Next.js application is not correctly listening on the port and host that Cloud Run expects.
Google Cloud Run operates by providing your container with a PORT environment variable (always 8080) and expects your application to bind to 0.0.0.0:$PORT. If your Next.js application, by default, attempts to listen on localhost:3000 (or any other port/host), Cloud Run’s internal proxy will be unable to reach it. Consequently:
- Health Checks Fail: Cloud Run’s readiness and liveness probes will time out, as the application isn’t responding on the expected interface.
- Container Termination: Cloud Run will eventually decide the container is unhealthy and terminate it.
- Broken Pipe: During shutdown or before it’s gracefully handled, any active processes (like Node.js itself trying to log to standard output/error) will attempt to write to pipes that are already closed by the terminating parent process or Cloud Run’s infrastructure, resulting in the “Broken Pipe” error.
Less common, but still possible, causes include:
- Unhandled Exceptions: Your Next.js app might be crashing immediately after startup due to an unhandled error, leading to a quick shutdown and subsequent broken pipe errors for any pending writes.
- Resource Exhaustion: Memory or CPU limits being hit, causing the container to be forcibly terminated.
However, for Next.js on Cloud Run, the port/host binding is overwhelmingly the most frequent culprit.
2. Quick Fix (CLI)
The fastest way to address the primary cause is to ensure your npm start command explicitly tells Next.js to use the PORT environment variable provided by Cloud Run.
-
Update your
package.json(locally): Modify yourstartscript to explicitly bind Next.js to thePORTenvironment variable.// package.json { "name": "my-nextjs-app", "version": "0.1.0", "private": true, "scripts": { "dev": "next dev", "build": "next build", "start": "next start -p $PORT", // <--- CRITICAL CHANGE "lint": "next lint" }, "dependencies": { "next": "latest", "react": "latest", "react-dom": "latest" } }next start -p $PORT: This command instructs Next.js to start its production server and listen on the port specified by thePORTenvironment variable. Cloud Run automatically setsPORTto8080inside your container.
-
Redeploy your service using
gcloud:Assuming you’ve updated your
package.jsonand rebuilt your Docker image (if using a Dockerfile), redeploy your service.gcloud run deploy YOUR_SERVICE_NAME \ --image gcr.io/YOUR_PROJECT_ID/YOUR_IMAGE_NAME:latest \ --platform managed \ --region YOUR_REGION \ --allow-unauthenticated # Or adjust access as neededReplace
YOUR_SERVICE_NAME,YOUR_PROJECT_ID,YOUR_IMAGE_NAME, andYOUR_REGIONwith your actual values.
This immediate change often resolves the “Broken Pipe” issue by correctly exposing your Next.js application to Cloud Run’s internal network.
3. Configuration Check
To ensure long-term stability and prevent recurrence, review these critical configuration files:
3.1. package.json
Verify the start script as mentioned in the Quick Fix section. This is the most crucial part.
// package.json
"scripts": {
"dev": "next dev",
"build": "next build",
"start": "next start -p $PORT", // Ensure this is correct
"lint": "next lint"
},
3.2. Dockerfile
Ensure your Dockerfile correctly builds the Next.js application and executes the start script.
# Stage 1: Install dependencies and build the application
FROM node:18-alpine AS builder
WORKDIR /app
COPY package.json yarn.lock ./
# If using npm: COPY package.json package-lock.json ./
RUN npm install --frozen-lockfile # Or yarn install --frozen-lockfile
COPY . .
RUN npm run build # Build the Next.js application
# Stage 2: Run the application
FROM node:18-alpine
WORKDIR /app
# Copy only necessary files from the builder stage
COPY --from=builder /app/.next ./.next
COPY --from=builder /app/node_modules ./node_modules
COPY --from=builder /app/package.json ./package.json
COPY --from=builder /app/public ./public
# If you have custom server.js or other necessary files, copy them as well
# Expose the port Cloud Run expects
EXPOSE 8080
# Command to run the application
# This will execute `npm start` which should then use `next start -p $PORT`
CMD ["npm", "start"]
Key Points in Dockerfile:
- Multi-stage build: Recommended for smaller image sizes.
RUN npm run build: Ensure your application is built before deployment. Next.js production mode requires a build.EXPOSE 8080: While Cloud Run doesn’t strictly requireEXPOSE, it’s good practice for clarity and container introspection.CMD ["npm", "start"]: This command executes thestartscript defined in yourpackage.json.
3.3. Cloud Run Service Configuration (Environment Variables)
While Cloud Run provides the PORT environment variable, it’s worth checking your service configuration for any overrides.
-
Via
gcloud:gcloud run services describe YOUR_SERVICE_NAME \ --platform managed \ --region YOUR_REGION \ --format='json' | jq '.spec.template.spec.containers[0].env'Look for any
PORTvariable you might have explicitly set that could override the default8080. If you see{"name": "PORT", "value": "3000"}, remove it, as this would force Next.js to listen on the wrong port. -
Via Google Cloud Console: Navigate to Cloud Run -> Your Service -> “REVISE & DEPLOY NEW REVISION” -> “Container, Networking, Security” tab -> “Variables & Secrets”. Ensure there’s no
PORTvariable explicitly set to anything other than8080(or preferably, just leave it unset to use Cloud Run’s default).
4. Verification
After applying the fixes, verify your deployment:
-
Check Cloud Run Logs: Go to your Cloud Run service in the Google Cloud Console, then navigate to the “Logs” tab. Look for messages from your application indicating it’s starting and listening on the correct port:
info - Ready on http://0.0.0.0:8080You should no longer see “Broken Pipe” errors or container crash messages immediately after startup.
-
Access the Service URL: Open your Cloud Run service’s URL in a web browser. Your Next.js application should load and function correctly.
-
Monitor Revisions: Ensure that new revisions deploy successfully and remain in a “Ready” state without frequent restarts. If the issue was critical port binding, new revisions should now be stable.
By systematically checking and correcting the port/host binding for your Next.js application on Cloud Run, you can reliably eliminate the “Broken Pipe” error and ensure a stable deployment.