{"record":{"id":"f2e8f1f51cf1a3a2","repo":"walkor/workerman","slug":"msg","errorCode":null,"errorMessage":"${msg}","messagePattern":"\\$\\{msg\\}","errorType":"exception","errorClass":"RuntimeException","httpStatus":null,"severity":"critical","filePath":"src/Worker.php","lineNumber":2536,"sourceCode":"     *\n     * @return void\n     */\n    protected static function checkPortAvailable(): void\n    {\n        foreach (static::$workers as $worker) {\n            $socketName = $worker->getSocketName();\n            if (DIRECTORY_SEPARATOR === '/'  // if linux\n                && static::$status === static::STATUS_STARTING // only for starting status\n                && $worker->transport === 'tcp' // if tcp socket\n                && !str_starts_with($socketName, 'unix') // if not unix socket\n                && !str_starts_with($socketName, 'udp')) { // if not udp socket\n\n                $address = parse_url($socketName);\n                if (isset($address['host']) && isset($address['port'])) {\n                    $address = \"tcp://{$address['host']}:{$address['port']}\";\n                    $server = null;\n                    set_error_handler(function ($code, $msg) {\n                        throw new RuntimeException($msg);\n                    });\n                    $server = stream_socket_server($address, $code, $msg);\n                    if ($server) {\n                        fclose($server);\n                    }\n                    restore_error_handler();\n                }\n            }\n        }\n    }\n\n    /**\n     * Parse local socket address.\n     */\n    protected function parseSocketAddress(): ?string\n    {\n        if (!$this->socketName) {\n            return null;","sourceCodeStart":2518,"sourceCodeEnd":2554,"githubUrl":"https://github.com/walkor/workerman/blob/1391112a61d23020e11e7b89f17050f6cfaea431/src/Worker.php#L2518-L2554","documentation":"Workerman runs Worker::checkPortAvailable() on Linux while the master process is in STATUS_STARTING: for every tcp (non-unix, non-udp) listener it does a probe stream_socket_server() bind and installs a set_error_handler that converts the PHP warning into this RuntimeException. So the message is the raw stream_socket_server warning, e.g. 'stream_socket_server(): unable to connect to tcp://0.0.0.0:8080 (Address already in use)'. The library throws it to fail fast, before forking worker processes, when the address cannot be bound.","triggerScenarios":"Running `php start.php start` (the runAll path sets STATUS_STARTING) on Linux when: another process (a previous Workerman instance, nginx, apache, a dev server) already listens on the same host:port; the port is <1024 and the process is not root/cap_net_bind_service; the host part of listen resolves to an address not available on the machine; or the address is otherwise invalid. Only workers with transport==='tcp' and a socketName not starting with 'unix'/'udp' are probed.","commonSituations":"Starting a second copy of the server while the old one is still alive (kill -9 left the socket held, or the stop command was skipped); deploying to a container/port mapping that collides with another service; switching to port 80/443 without privileges; porting a config that worked on macOS/Windows (the probe only runs when DIRECTORY_SEPARATOR === '/').","solutions":["Find and stop the process holding the port: `ss -ltnp 'sport = :8080'` or `lsof -i :8080`, then `php start.php stop` (or kill the PID) and start again.","If the other listener is intentional and you want several instances sharing the port, set `$worker->reusePort = true;` on Linux (SO_REUSEPORT).","Change to a free port in the Worker constructor, e.g. `new Worker('http://0.0.0.0:8081')`.","For ports below 1024, run with adequate privilege or grant the PHP binary the capability once: `sudo setcap 'cap_net_bind_service=+ep' $(which php)`.","If the host part is wrong (typo like 0.0.0.1 or an IP not on the machine), correct it to a local address such as 127.0.0.1 or 0.0.0.0."],"exampleFix":"// before: second instance while the first still holds the port\n$worker = new Worker('http://0.0.0.0:8080');\nWorker::runAll(); // RuntimeException: stream_socket_server(): unable to connect to tcp://0.0.0.0:8080 (Address already in use)\n\n// after: stop the old instance first, or opt into port sharing\n$worker = new Worker('http://0.0.0.0:8080');\n$worker->reusePort = true; // SO_REUSEPORT, allows multiple listeners on Linux\nWorker::runAll();","handlingStrategy":"validation","validationCode":"// Probe the port before handing control to Workerman\n$listen = '0.0.0.0:8080';\n$probe = @stream_socket_server(\"tcp://$listen\", $errno, $errstr);\nif ($probe === false) {\n    fwrite(STDERR, \"Cannot bind $listen: $errstr\\n\");\n    exit(1);\n}\nfclose($probe); // release it so Workerman can bind\n\n$worker = new Worker(\"http://$listen\");\nWorker::runAll();","typeGuard":null,"tryCatchPattern":"try {\n    Worker::runAll();\n} catch (RuntimeException $e) {\n    if (str_contains($e->getMessage(), 'Address already in use')) {\n        // port conflict: report PID hint and exit non-zero\n        fwrite(STDERR, $e->getMessage() . \"\\nRun: php start.php stop\\n\");\n        exit(1);\n    }\n    throw $e;\n}","preventionTips":["Always stop with `php start.php stop`/`reload` instead of kill -9 so the master releases ports cleanly.","In containers/CI, assert the port is free (or use SO_REUSEPORT via $worker->reusePort on Linux) before start.","Keep ports per-environment in config and reserve them so two services never claim the same one."],"tags":["workerman","port-in-use","socket-bind","startup","php"],"backgroundTag":"address-already-in-use","analyzedSha":"1391112a61d23020e11e7b89f17050f6cfaea431","analyzedAt":"2026-08-21T02:05:46.744Z","schemaVersion":2},"datasetVersion":"2026-08-21T03:17:12.404Z"}