{"record":{"id":"e61952ed754a64de","repo":"ratchetphp/Ratchet","slug":"request-can-not-be-null","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/Http/Router.php","lineNumber":32,"sourceCode":"     * @var \\Symfony\\Component\\Routing\\Matcher\\UrlMatcherInterface\n     */\n    protected $_matcher;\n\n    private $_noopController;\n\n    public function __construct(UrlMatcherInterface $matcher) {\n        $this->_matcher = $matcher;\n        $this->_noopController = new NoOpHttpServerController;\n    }\n\n    /**\n     * {@inheritdoc}\n     * @throws \\UnexpectedValueException If a controller is not \\Ratchet\\Http\\HttpServerInterface\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->controller = $this->_noopController;\n\n        $uri = $request->getUri();\n\n        $context = $this->_matcher->getContext();\n        $context->setMethod($request->getMethod());\n        $context->setHost($uri->getHost());\n\n        try {\n            $route = $this->_matcher->match($uri->getPath());\n        } catch (MethodNotAllowedException $nae) {\n            return $this->close($conn, 405, array('Allow' => $nae->getAllowedMethods()));\n        } catch (ResourceNotFoundException $nfe) {\n            return $this->close($conn, 404);\n        }\n","sourceCodeStart":14,"sourceCodeEnd":50,"githubUrl":"https://github.com/ratchetphp/Ratchet/blob/e621c6c40bf684bbbb877102416ad5303d05a9cc/src/Ratchet/Http/Router.php#L14-L50","documentation":"Ratchet's Http\\Router::onOpen() receives the PSR-7 RequestInterface that was attached to the connection by an upstream HttpServer component. It throws UnexpectedValueException immediately when $request is null, because routing (host/path matching) is impossible without a request. This guards against the Router being wired into a stack that never injects a request, or onOpen() being called directly with only a connection.","triggerScenarios":"Calling Router::onOpen($conn) manually without the second argument; putting Router directly under IoServer instead of under HttpServer (which normally provides the PSR-7 request); a custom middleware/component in the socket stack that consumes or fails to re-attach the request before Router runs.","commonSituations":"Reordering components in the app stack so Router runs before HttpServer; unit tests invoking onOpen with a mock connection only; upgrading Ratchet or swapping the HTTP handshake component so the request no longer reaches the Router.","solutions":["Ensure Router sits under an HttpServer component: new IoServer(new HttpServer(new Router(...), ...), ...) so onOpen receives a PSR-7 request.","If invoking onOpen in tests, pass a valid RequestInterface instance implementing PSR-7 (e.g. GuzzleHttp\\Psr7\\ServerRequest) as the second argument.","Audit any custom components between HttpServer and Router to confirm they preserve $conn->httpHeadersReceived / forward the request rather than calling onOpen($conn) themselves.","Verify you are not wrapping Router directly in WsServer/IoServer in a way that bypasses the HTTP handshake that produces the request."],"exampleFix":"// before\n$server = new IoServer(new Router($routeParser), $sock, $loop);\n\n// after\nuse Ratchet\\Http\\HttpServer;\n$server = new IoServer(new HttpServer(new Router($routeParser)), $sock, $loop);","handlingStrategy":"try-catch","validationCode":"use Psr\\Http\\Message\\RequestInterface;\nif (!isset($request) || !$request instanceof RequestInterface) {\n    throw new \\LogicException('Router::onOpen requires a PSR-7 RequestInterface; mount Router under HttpServer.');\n}","typeGuard":"function hasRequest($conn): bool {\n    return isset($conn->httpHeadersReceived) && $conn->httpHeadersReceived instanceof \\Psr\\Http\\Message\\RequestInterface;\n}","tryCatchPattern":"try {\n    $router->onOpen($conn, $request);\n} catch (\\UnexpectedValueException $e) {\n    if ($e->getMessage() === '$request can not be null') {\n        $conn->close(); // stack misconfigured: Router never receives a request\n    } else { throw $e; }\n}","preventionTips":["Always mount Router beneath Ratchet\\Http\\HttpServer in the component stack.","In tests, construct a real PSR-7 request (GuzzleHttp\\Psr7\\ServerRequest) rather than passing only a connection.","Never call Router::onOpen($conn) with one argument; grep for that pattern in middleware.","Keep HttpServer as the immediate parent of Router when composing components."],"tags":["php","ratchet","psr7","websocket"],"backgroundTag":"null-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"}