How to Fix Next.js Broken Pipe on CentOS 7
Troubleshooting “Next.js Broken Pipe” on CentOS 7
As Senior DevOps Engineers, we often encounter subtle system-level issues manifesting as application errors. One such common problem, particularly when deploying Node.js-based applications like Next.js on CentOS 7, is the dreaded “Broken Pipe” error (EPIPE). This guide will help you diagnose and resolve this issue.
1. The Root Cause: CentOS 7’s System Defaults
The “Broken Pipe” error (EPIPE) in the context of a Next.js application on CentOS 7 almost invariably points to insufficient system resource limits, specifically the number of open file descriptors (FDs).
Why this happens on CentOS 7:
- Default
ulimit -n: CentOS 7, by default, often has a relatively lowulimit -n(number of open files) set for non-root users, frequently 1024 or 4096. - Next.js Resource Usage:
- During
next build: The build process for complex Next.js applications can involve a significant number of file operations – reading source files, writing compiled assets, traversing dependency trees, and potentially spawning child processes. Each file or network socket opened consumes a file descriptor. - During Runtime: A running Next.js server (especially under load or serving many concurrent requests) will open numerous network sockets (for client connections, database connections, API calls, etc.), static assets, and log files. Each active connection or file stream consumes an FD.
- During
- The Breakdown: When the Next.js application (or one of its child processes) attempts to open a file or create a socket, and the number of currently open FDs for that user/process exceeds its
ulimit -nsoft limit, the operation fails. If the application then tries to write to a resource whose underlying FD was closed or never opened successfully due to this limit, you get anEPIPEerror, indicating that the write failed because the receiving end of the pipe (or socket) is no longer available.
While less common for a single application, other limits like nproc (number of processes) or the system-wide fs.file-max could also contribute if the issue is severe or involves many concurrent services.
2. Quick Fix (CLI - Temporary)
To immediately alleviate the issue for your current session and test if resource limits are indeed the problem, you can temporarily raise the file descriptor limit for the user running the Next.js application.
-
Identify the User: Determine which user account your Next.js application runs under (e.g.,
webuser,node,nginx, or a dedicated service user). -
Switch to the User (if necessary):
sudo su - <username> # Replace <username> with your application's user -
Check Current Limits:
ulimit -nYou will likely see a value like
1024or4096. -
Set New Temporary Limit: Choose a significantly higher value.
65536is a common safe starting point.ulimit -n 65536 -
Verify New Limit:
ulimit -n -
Restart Next.js Application: Stop and restart your Next.js application within this same shell session where you set the
ulimit. If you’re using PM2, ensure you restart it as the user with the elevated limits.# Example for a Next.js app started directly # (replace with your actual start command, e.g., 'npm start', 'yarn start', 'pm2 start index.js') npm run build # if the error occurs during build npm start
If the “Broken Pipe” error disappears, you’ve confirmed that file descriptor limits were the root cause. Now, you need to make these changes persistent.
3. Configuration Check (Permanent Fix)
For a robust and persistent solution, you need to modify system configuration files.
a. For All Sessions / Specific Users (/etc/security/limits.conf)
This file manages resource limits for users logging in via PAM (Pluggable Authentication Modules), which includes direct SSH logins and services started without systemd unit files (e.g., PM2 started by a user).
-
Edit
limits.conf:sudo vi /etc/security/limits.conf -
Add or Modify Entries: Add the following lines at the end of the file, replacing
<username>with the actual user running your Next.js application. If you want this to apply to all non-root users, use*.# <domain> <type> <item> <value> <username> soft nofile 65536 <username> hard nofile 65536 # Optional: If you also suspect process limits # <username> soft nproc 4096 # <username> hard nproc 4096softlimit: The limit that is enforced for a user at login. It can be increased by the user up to thehardlimit.hardlimit: The maximum limit that the user can ever set. Only root can increase a hard limit.nofile: Refers to the maximum number of open file descriptors.nproc: Refers to the maximum number of processes a user can own.
-
Save and Exit.
-
Reboot or Re-login: For these changes to take effect, the user needs to log out and log back in, or the system needs to be rebooted.
b. For systemd Managed Services
If your Next.js application is managed by a systemd service unit (highly recommended for production), you should specify the limits directly in its unit file.
-
Identify Service File: Your service file might be located at
/etc/systemd/system/nextjs.serviceor/usr/lib/systemd/system/nextjs.service. -
Edit the Service File:
sudo vi /etc/systemd/system/nextjs.service -
Add Limits to
[Service]Section: Locate the[Service]section and add theLimitNOFILEandLimitNPROCdirectives.[Service] # ... existing configurations ... User=<username> # Ensure this matches your app's user Group=<groupname> # Ensure this matches your app's group LimitNOFILE=65536 # Set the max open files for this service LimitNPROC=4096 # Optional: Set max processes if needed # ... more configurations ... -
Reload
systemdand Restart Service:sudo systemctl daemon-reload sudo systemctl restart nextjs.service # Replace 'nextjs.service' with your actual service name
c. System-Wide File Descriptor Limit (/etc/sysctl.conf)
While less frequently the primary cause than ulimit -n, it’s good practice to ensure the system-wide limit for file descriptors is also sufficiently high, especially on busy servers.
- Check Current System Limit:
sysctl fs.file-max - Edit
sysctl.conf:sudo vi /etc/sysctl.conf - Add or Modify Entry:
Add or update the following line. A common value for
fs.file-maxon a production server is between250000and1000000.fs.file-max = 500000 - Save and Exit.
- Apply Changes:
sudo sysctl -p
4. Verification
After applying the permanent fixes, it’s crucial to verify that the changes have taken effect and that your Next.js application is stable.
-
Verify Limits for the Running Process: This is the most direct way to confirm your application is running with the desired limits.
- Find Next.js Process ID (PID):
Note down the PID of your main Next.js process.pgrep -a node | grep nextjs # Adjust 'grep nextjs' if your app has a different identifier # Or more generally: ps aux | grep node - Check Process Limits:
Look for the “Max open files” line. It should reflect the newcat /proc/<PID>/limits # Replace <PID> with the actual process ID65536soft and hard limits.
- Find Next.js Process ID (PID):
-
Monitor Logs: Check your application’s logs for any recurring “Broken Pipe” or resource exhaustion errors.
- If using
systemd:sudo journalctl -u nextjs.service -f # Replace 'nextjs.service' - If logging to a file:
tail -f /path/to/your/nextjs/app.log
- If using
-
Simulate Load (Stress Test): If the error primarily occurred under load or during build, simulate those conditions to confirm stability.
- For build issues: Rerun
npm run buildoryarn buildmultiple times. - For runtime issues: Use a load testing tool like ApacheBench (
ab),wrk, ork6to send a high volume of requests to your Next.js server.
Observe both the load test results and your application logs for any errors.# Example using ApacheBench sudo yum install httpd-tools -y # If not already installed ab -n 10000 -c 100 http://localhost:3000/ # 10,000 requests, 100 concurrent
- For build issues: Rerun
By systematically applying these steps, you should successfully resolve the “Next.js Broken Pipe” error on CentOS 7, ensuring your application runs reliably even under demanding conditions.