{"record":{"id":"df6a37647e931841","repo":"ratchetphp/Ratchet","slug":"request-can-not-be-null-wsserver","errorCode":null,"errorMessage":"$request can not be null","messagePattern":"\\$request can not be null","errorType":"exception","errorClass":"UnexpectedValueException","httpStatus":null,"severity":"error","filePath":"src/Ratchet/WebSocket/WsServer.php","lineNumber":122,"sourceCode":"\n        $reusableUnderflowException = new \\UnderflowException;\n        $this->ueFlowFactory = function() use ($reusableUnderflowException) {\n            return $reusableUnderflowException;\n        };\n    }\n\n    private static function isRFC6455v03() {\n        $reflection = new \\ReflectionClass('Ratchet\\RFC6455\\Handshake\\ServerNegotiator');\n        return $reflection->getMethod('__construct')->getNumberOfRequiredParameters() === 1;\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    #[HackSupportForPHP8] public function onOpen(ConnectionInterface $conn, ?RequestInterface $request = null) { /*\n    public function onOpen(ConnectionInterface $conn, RequestInterface $request = null) { /**/\n        if (null === $request) {\n            throw new \\UnexpectedValueException('$request can not be null');\n        }\n\n        $conn->httpRequest = $request;\n\n        $conn->WebSocket            = new \\StdClass;\n        $conn->WebSocket->closing   = false;\n\n        $response = $this->handshakeNegotiator->handshake($request)->withHeader('X-Powered-By', \\Ratchet\\VERSION);\n\n        $conn->send(Message::toString($response));\n\n        if (101 !== $response->getStatusCode()) {\n            return $conn->close();\n        }\n\n        $wsConn = new WsConnection($conn);\n\n        $streamer = new MessageBuffer(","sourceCodeStart":104,"sourceCodeEnd":140,"githubUrl":"https://github.com/ratchetphp/Ratchet/blob/e621c6c40bf684bbbb877102416ad5303d05a9cc/src/Ratchet/WebSocket/WsServer.php#L104-L140","documentation":"WsServer::onOpen performs the WebSocket handshake and stores the HTTP upgrade request on the connection, so it requires the PSR-7 RequestInterface argument. When onOpen is invoked with a null request — meaning no HTTP request reached this component — an UnexpectedValueException is thrown because the handshake cannot proceed.","triggerScenarios":"Calling WsServer::onOpen($conn) directly without a RequestInterface (it is optional only for interface compatibility); wiring WsServer at the top of the component stack so it receives connections before an HTTP-processing middleware (e.g. HttpServer/router) populated the request; connections that bypassed the HTTP upgrade path.","commonSituations":"Stacking components in the wrong order in IoServer (WsServer must sit below/after HttpServer so it gets the parsed request); testing onOpen manually in unit tests; using a frontend proxy setup where the request object is stripped.","solutions":["Ensure HttpServer (which parses the HTTP request) wraps WsServer: new IoServer(new HttpServer(new WsServer($app)), ...) so onOpen receives the RequestInterface.","When calling onOpen yourself (tests/custom pipelines), pass a PSR-7 RequestInterface instance, e.g. new \\GuzzleHttp\\Psr7\\ServerRequest('GET', '/').","If using a router (Router/OriginCheck) keep it around WsServer so the request is forwarded, not consumed."],"exampleFix":"// before\nnew \\Ratchet\\Server\\IoServer(new \\Ratchet\\WebSocket\\WsServer($chat), $sock); // WsServer gets null request\n// after\nnew \\Ratchet\\Server\\IoServer(\n    new \\Ratchet\\Http\\HttpServer(\n        new \\Ratchet\\WebSocket\\WsServer($chat)\n    ),\n    $sock\n);","handlingStrategy":"type-guard","validationCode":"if (null === $request) {\n    // refuse to call WsServer::onOpen without an HTTP request\n    throw new \\LogicException('Wrap WsServer in HttpServer so onOpen receives a RequestInterface');\n}\n$wsServer->onOpen($conn, $request);","typeGuard":"function hasHandshakeRequest(?\\Psr\\Http\\Message\\RequestInterface $r): bool { return $r !== null; }","tryCatchPattern":"try {\n    $wsServer->onOpen($conn, $request);\n} catch (\\UnexpectedValueException $e) {\n    $conn->close(); // cannot handshake without the request\n}","preventionTips":["Always stack HttpServer around WsServer in IoServer so the upgrade request is parsed first.","Never call onOpen on WsServer directly in tests without a PSR-7 RequestInterface.","Keep routers/middleware ordered so the request object reaches WsServer instead of being consumed upstream.","Document that WsServer must not be the outermost component."],"tags":["php","websocket","http","handshake"],"backgroundTag":"missing-required-argument","analyzedSha":"e621c6c40bf684bbbb877102416ad5303d05a9cc","analyzedAt":"2026-09-16T00:13:27.878Z","contentChangedAt":"2026-09-16T00:13:27.878Z","schemaVersion":2},"datasetVersion":"2026-09-16T04:17:20.429Z"}