ratchetphp/Ratchet · error · UnexpectedValueException
$request can not be null
Error message
$request can not be null
What it means
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.
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.
Example fix
// before
new \Ratchet\Server\IoServer(new \Ratchet\WebSocket\WsServer($chat), $sock); // WsServer gets null request
// after
new \Ratchet\Server\IoServer(
new \Ratchet\Http\HttpServer(
new \Ratchet\WebSocket\WsServer($chat)
),
$sock
); Defensive patterns
Strategy: type-guard
Validate before calling
if (null === $request) {
// refuse to call WsServer::onOpen without an HTTP request
throw new \LogicException('Wrap WsServer in HttpServer so onOpen receives a RequestInterface');
}
$wsServer->onOpen($conn, $request); Type guard
function hasHandshakeRequest(?\Psr\Http\Message\RequestInterface $r): bool { return $r !== null; } Try / catch
try {
$wsServer->onOpen($conn, $request);
} catch (\UnexpectedValueException $e) {
$conn->close(); // cannot handshake without the request
} Prevention
- 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.
When it happens
Trigger: 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.
Common situations: 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.
Understand the failure class
Background: "missing required argument" and "the following required arguments were not provided": what required-argument errors mean and how to fix them — this error's family across 20 libraries.
Related errors
- Maximum buffer size of
- $request can not be null
- Expected instance of…
- Invalid WAMP message format
- Invalid Topic, must be a string
AI-assisted analysis of ratchetphp/Ratchet@e621c6c40b (2026-09-16).
Data as JSON: /api/errors/df6a37647e931841.
Report an issue: GitHub.
Appendix: source
Thrown at src/Ratchet/WebSocket/WsServer.php:122
$reusableUnderflowException = new \UnderflowException;
$this->ueFlowFactory = function() use ($reusableUnderflowException) {
return $reusableUnderflowException;
};
}
private static function isRFC6455v03() {
$reflection = new \ReflectionClass('Ratchet\RFC6455\Handshake\ServerNegotiator');
return $reflection->getMethod('__construct')->getNumberOfRequiredParameters() === 1;
}
/**
* {@inheritdoc}
*/
#[HackSupportForPHP8] public function onOpen(ConnectionInterface $conn, ?RequestInterface $request = null) { /*
public function onOpen(ConnectionInterface $conn, RequestInterface $request = null) { /**/
if (null === $request) {
throw new \UnexpectedValueException('$request can not be null');
}
$conn->httpRequest = $request;
$conn->WebSocket = new \StdClass;
$conn->WebSocket->closing = false;
$response = $this->handshakeNegotiator->handshake($request)->withHeader('X-Powered-By', \Ratchet\VERSION);
$conn->send(Message::toString($response));
if (101 !== $response->getStatusCode()) {
return $conn->close();
}
$wsConn = new WsConnection($conn);
$streamer = new MessageBuffer(View on GitHub (pinned to e621c6c40b)