walkor/workerman · error · RuntimeException

can not save pid to ${static::$pidFile}

Error message

can not save pid to ${static::$pidFile}

What it means

On startup the master process writes its PID to Worker::$pidFile (default under sys_get_temp_dir()) so stop/reload/status commands can find it. file_put_contents() returning false means the file could not be written - missing directory, permission denied, read-only filesystem, or disk full - and Workerman aborts because process management would be broken.

Source

Thrown at src/Worker.php:1506

        if (function_exists('posix_isatty') && posix_isatty(2)) {
            ob_start(function (string $string) {
                file_put_contents(static::$stdoutFile, $string, FILE_APPEND);
            }, 1);
        }
    }

    /**
     * Save pid.
     */
    protected static function saveMasterPid(): void
    {
        if (DIRECTORY_SEPARATOR !== '/') {
            return;
        }

        static::$masterPid = posix_getpid();
        if (false === file_put_contents(static::$pidFile, static::$masterPid)) {
            throw new RuntimeException('can not save pid to ' . static::$pidFile);
        }
    }

    /**
     * Get all pids of worker processes.
     *
     * @return array
     */
    protected static function getAllWorkerPids(): array
    {
        $pidArray = [];
        foreach (static::$pidMap as $workerPidArray) {
            foreach ($workerPidArray as $workerPid) {
                $pidArray[$workerPid] = $workerPid;
            }
        }
        return $pidArray;
    }

View on GitHub (pinned to 1391112a61)

Solutions

  1. Point the pid file at a writable location for the run user, e.g. Worker::$pidFile = '/var/run/myapp/workerman.pid' after creating and chown-ing that directory
  2. Check the directory exists and the user can write: 'sudo -u appuser touch <dir>/test'
  3. Remove a stale pid file left by a root run: 'sudo rm <pidFile>'

Example fix

// before
Worker::$pidFile = '/var/run/workerman.pid'; // /var/run not writable by app user
Worker::runAll(); // 'can not save pid to /var/run/workerman.pid'

// after
Worker::$pidFile = '/var/run/myapp/workerman.pid';
// provisioned once at deploy: mkdir -p /var/run/myapp && chown appuser /var/run/myapp
Worker::runAll();
Defensive patterns

Strategy: validation

Validate before calling

$pidFile = '/var/run/myapp/workerman.pid';
$dir = dirname($pidFile);
if (!is_dir($dir) || !is_writable($dir)) {
    throw new RuntimeException("pid directory $dir missing or not writable");
}
Worker::$pidFile = $pidFile;

Prevention

When it happens

Trigger: Custom Worker::$pidFile = '/var/run/workerman.pid' with /var/run not writable by the runtime user; the target directory was deleted; a stale pid file owned by root while the service now runs as an unprivileged user on a read-only-ish path; disk full.

Common situations: Hardening a service to run as non-root without adjusting the pidFile path; switching between root and app-user starts; container images with read-only root filesystems; /tmp cleaned by tmpfiles.d while using the default path assumptions.

Related errors


AI-assisted analysis of walkor/workerman@1391112a61 (2026-08-21). Data as JSON: /api/errors/778a9ec9c08c86f0. Report an issue: GitHub.