{"record":{"id":"1bbe8d2f95a114ac","repo":"sebastianbergmann/phpunit","slug":"cannot-open-socket-s-d","errorCode":null,"errorMessage":"Cannot open socket %s:%d","messagePattern":"Cannot open socket (.+?):(.+?)","errorType":"exception","errorClass":"PHPUnit\\TextUI\\CannotOpenSocketException","httpStatus":null,"severity":"error","filePath":"src/TextUI/Output/Printer/DefaultPrinter.php","lineNumber":90,"sourceCode":"     * @throws CannotOpenSocketException\n     * @throws DirectoryDoesNotExistException\n     * @throws InvalidSocketException\n     */\n    private function __construct(string $out)\n    {\n        $this->isPhpStream = str_starts_with($out, 'php://');\n\n        if (str_starts_with($out, 'socket://')) {\n            $tmp = explode(':', str_replace('socket://', '', $out));\n\n            if (count($tmp) !== 2) {\n                throw new InvalidSocketException($out);\n            }\n\n            $stream = @fsockopen($tmp[0], (int) $tmp[1]);\n\n            if ($stream === false) {\n                throw new CannotOpenSocketException($tmp[0], (int) $tmp[1]);\n            }\n\n            $this->stream = $stream;\n            $this->isOpen = true;\n\n            return;\n        }\n\n        if (!$this->isPhpStream && !Filesystem::createDirectory(dirname($out))) {\n            throw new DirectoryDoesNotExistException(dirname($out));\n        }\n\n        $stream = fopen($out, 'wb');\n\n        assert($stream !== false);\n\n        $this->stream = $stream;\n        $this->isOpen = true;","sourceCodeStart":72,"sourceCodeEnd":108,"githubUrl":"https://github.com/sebastianbergmann/phpunit/blob/f123cdb2a2d49f15025794166cfed8bda8627dd2/src/TextUI/Output/Printer/DefaultPrinter.php#L72-L108","documentation":"DefaultPrinter is PHPUnit's output sink for progress and test-result output. When its constructor receives a target like `socket://host:port`, it strips the scheme, splits host and port, and calls @fsockopen(). If the TCP connection cannot be established, it throws CannotOpenSocketException('Cannot open socket host:port'). PHPUnit aborts at startup because it cannot deliver output to the configured destination.","triggerScenarios":"Calling DefaultPrinter::from('socket://127.0.0.1:9000') (or configuring an equivalent output target) when no server is listening on that host/port, the port is mistyped, the hostname does not resolve, or a firewall/network barrier drops the connection. The string must be exactly `socket://hostname:port`; anything else is treated as a file path (php:// streams excepted).","commonSituations":"CI pipelines that ship test output to a log-collector socket (Logstash, Datadog agent, custom TCP sink) that has not been started yet; Docker setups where 'localhost' resolves inside the wrong container; port typos after changing the collector's configuration.","solutions":["Verify something is listening and reachable from the test runner: `nc -vz host port` or `ss -ltn` / `docker port`, then start the receiver before running PHPUnit","Fix the host/port in the target string; the parser expects exactly `socket://hostname:port` (two colon-separated parts after the scheme)","In containerized or firewalled environments, connect to the address as seen from the test container, not the host's loopback","If you never intended a socket, remove the `socket://` prefix — any non-`php://` target without that scheme is opened as a regular file"],"exampleFix":"// before\n$printer = \\PHPUnit\\TextUI\\Output\\Printer\\DefaultPrinter::from('socket://127.0.0.1:9988');\n// Throws CannotOpenSocketException: nothing listens on 9988\n\n// after: start the receiver first, or target a file\n$ ls: $ nc -l 127.0.0.1 9988 &\n$printer = \\PHPUnit\\TextUI\\Output\\Printer\\DefaultPrinter::from('socket://127.0.0.1:9988');\n// or simply write to a file:\n$printer = \\PHPUnit\\TextUI\\Output\\Printer\\DefaultPrinter::from('build/logs/output.txt');","handlingStrategy":"try-catch","validationCode":"$target = 'socket://127.0.0.1:9988';\nif (str_starts_with($target, 'socket://')) {\n    [$host, $port] = explode(':', substr($target, 9));\n    $probe = @fsockopen($host, (int) $port, $errno, $errstr, 3);\n    if ($probe === false) {\n        throw new RuntimeException(\"Output sink unavailable: $errstr ($errno)\");\n    }\n    fclose($probe);\n}","typeGuard":null,"tryCatchPattern":"use PHPUnit\\TextUI\\Output\\Printer\\CannotOpenSocketException;\n\ntry {\n    $printer = DefaultPrinter::from($target);\n} catch (CannotOpenSocketException $e) {\n    // degrade gracefully instead of aborting the run\n    $printer = DefaultPrinter::standardOutput();\n    error_log('Socket output unavailable, falling back to stdout: ' . $e->getMessage());\n}","preventionTips":["Start and health-check the socket receiver before invoking PHPUnit (a 1-line nc/timeout probe in the pipeline)","Pin the target to exactly `socket://host:port` — three or more colon-separated parts raise InvalidSocketException instead","In containers, always address the collector by the service name/IP reachable from the test container, never 127.0.0.1 by habit"],"tags":["phpunit","socket","output","network","tcp"],"backgroundTag":"socket-connection-failed","analyzedSha":"f123cdb2a2d49f15025794166cfed8bda8627dd2","analyzedAt":"2026-08-23T01:20:58.058Z","schemaVersion":2},"datasetVersion":"2026-08-23T08:06:27.607Z"}