Quick answer
Check your per-user process limit with ulimit -u and your cgroup pids limit with cat /sys/fs/cgroup/pids/pids.max, then raise them if needed. But first, kill orphaned processes or zombies — they're usually the real cause.
What's actually happening here
The fork() system call creates a new process by copying the calling process. When the kernel refuses to fork, it returns EAGAIN, which bash reports as "Resource temporarily unavailable." The kernel has three hard limits that trigger this: the global pid_max, the per-user process count (RLIMIT_NPROC), and the cgroup pids controller. On modern systemd distros, the cgroup limit is often the silent killer — you'll see the error even when ulimit -u looks fine.
This shows up in real scenarios like when a Python script spawns hundreds of threads, or a runaway cron job forks without cleaning up children. I've also seen it after a memory leak — when the system runs out of memory, fork fails with the same message because the kernel can't allocate the task struct or stack.
Fix it: step by step
- See how many processes you're using
Compare this to your limits. The number will be lower than the limit because bash itself counts, but you get the idea.ps -u $(whoami) | wc -l - Check your ulimits
If this shows something likeulimit -u1024or512, that's your per-user process ceiling. You can raise it for the current shell:
But that only affects the current shell — you need to set it permanently inulimit -u 4096/etc/security/limits.confor a file in/etc/security/limits.d/. Add this line:
Log out and back in for it to take effect.username soft nproc 4096 username hard nproc 8192 - Check the cgroup pids limit
If it shows a number likecat /sys/fs/cgroup/pids/pids.max512, that's your problem. On systemd systems, you can raise it for your user slice with:
This writes a drop-in file undersystemctl set-property user-$(id -u).slice TasksMax=4096/etc/systemd/system.control/. To make it permanent, create/etc/systemd/system/user-1000.slice.d/override.conf(replace 1000 with your UID) and put:
Then reload systemd:[Slice] TasksMax=8192systemctl daemon-reload. - Look at the global pid_max
Default is usuallycat /proc/sys/kernel/pid_max32768or4194304on 64-bit. If you're hitting this, you have way bigger problems — check for a fork bomb. Set it higher withsysctl -w kernel.pid_max=65536if you must, but this is a band-aid. - Kill orphaned processes
Look for processes withps -u $(whoami) -o pid,ppid,stat,cmdPPIDof 1 (orphans) orZin theSTATcolumn (zombies). Zombies can't be killed withkill— you have to kill their parent. If the parent is init (PID 1), reboot to clear them, or better, find what's spawning them.
When the main fix doesn't work
If you've raised limits and still see the error, check memory pressure:
free -h
If free memory is near zero, the kernel can't allocate stack space for new processes. A memory leak in a running app will do this. Find the culprit with top sorted by memory (M key), then kill it. Also check for thread exhaustion — each thread counts as a process for RLIMIT_NPROC, so a single Java app with 5000 threads can blow the limit.
Another angle: check if you're inside a container. Docker and Kubernetes set their own pids limits. Look at /sys/fs/cgroup/pids/pids.max inside the container — it might be lower than you expect. If you're in Kubernetes, the pod spec might have a pidsLimit set.
Prevention
The only reliable way to avoid this is to monitor your process count and know your limits before you hit them. Set a cron job that alerts you when your process count exceeds 80% of your limit:
*/5 * * * * [ $(ps -u $(whoami) | wc -l) -gt 2000 ] && echo "Process count high" | mail -s "Fork risk" you@example.com
Also, make your scripts clean up after themselves. If you're writing a daemon, set RLIMIT_NPROC explicitly in code with setrlimit(). And if you see zombies, don't ignore them — they're your app not calling wait() properly. Fix that, and you won't see this error again.
The root cause is almost always a misconfigured limit or a forgotten child process. The kernel isn't being mean — it's enforcing a contract you didn't know you signed.