walkor/workerman · critical · RuntimeException
Fork fail
Error message
Fork fail
What it means
When starting in daemon mode (-d/--daemon), Worker::daemonize() forks to detach from the terminal. pcntl_fork() returned -1, meaning the OS refused to create the process - typically because a process limit was hit (RLIMIT_NPROC, cgroup pids.max in containers) or memory could not be allocated for the child.
Source
Thrown at src/Worker.php:1438
SIGUSR2 => 'SIGUSR2',
SIGIOT => 'SIGIOT',
SIGIO => 'SIGIO',
default => $signal,
};
}
/**
* Run as daemon mode.
*/
protected static function daemonize(): void
{
if (!static::$daemonize || DIRECTORY_SEPARATOR !== '/') {
return;
}
umask(0);
$pid = pcntl_fork();
if (-1 === $pid) {
throw new RuntimeException('Fork fail');
} elseif ($pid > 0) {
exit(0);
}
if (-1 === posix_setsid()) {
throw new RuntimeException("Setsid fail");
}
// Fork again avoid SVR4 system regain the control of terminal.
$pid = pcntl_fork();
if (-1 === $pid) {
throw new RuntimeException("Fork fail");
} elseif (0 !== $pid) {
exit(0);
}
}
/**
* Redirect standard output to stdoutFile.
*View on GitHub (pinned to 1391112a61)
Solutions
- Raise the limits: 'ulimit -u 65535' (or the systemd/container equivalent, e.g. docker run --pids-limit=-1 or a higher K8s pid limit)
- Count actual usage with 'ps -eLf | wc -l' or the cgroup pids.current file to see what is exhausting the ceiling
- As a workaround, run without -d (foreground) to isolate whether the daemonize fork specifically is the blocker, and reduce total worker processes
Example fix
# before
php start.php start -d # master at nproc/pids limit -> RuntimeException('Fork fail')
# after
ulimit -u 65535 # or raise docker --pids-limit / k8s pod pids limit
php start.php start -d Defensive patterns
Strategy: validation
Validate before calling
$soft = posix_getrlimit(); // before starting with -d
if (isset($soft['RLIMIT_NPROC']) && $soft['RLIMIT_NPROC'] !== 'unlimited' && $soft['RLIMIT_NPROC'] < 1024) {
fwrite(STDERR, "RLIMIT_NPROC={$soft['RLIMIT_NPROC']} is low; fork may fail - raise it before daemonizing\n");
} Prevention
- Provision ulimit -u / container pids limits with headroom for all worker processes plus the two daemonize forks
- Set process ceilings in deployment manifests, not by trial at runtime
When it happens
Trigger: Running 'php start.php start -d' on a host already at its user process limit; Docker/Kubernetes with a low --pids-limit or pod pids cgroup ceiling; fork attempted while memory overcommit refuses the copy.
Common situations: Shared servers with tight ulimit -u; containers with default pids limits while the app forks many workers; CI environments restricting process creation; systems recovering from a fork-bomb incident with lowered limits.
Related errors
- Setsid fail
- forkOneWorker fail
- Bad remoteAddress
- Invalid protocol scheme '$scheme'
- class \Protocols\$scheme not exist
AI-assisted analysis of walkor/workerman@1391112a61 (2026-08-21).
Data as JSON: /api/errors/7061d86b744d70bf.
Report an issue: GitHub.