ratchetphp/Ratchet · error · InvalidArgumentException
Handler must be instance of SessionHandlerInterface
Error message
Handler must be instance of SessionHandlerInterface
What it means
VirtualSessionStorageForSymfony7::setSaveHandler accepts AbstractProxy|\SessionHandlerInterface|null but explicitly rejects any non-\SessionHandlerInterface value (including Symfony AbstractProxy instances) with an InvalidArgumentException. The typed check exists because the handler must be wrappable in Ratchet's VirtualProxy for virtual sessions. Passing an AbstractProxy — accepted elsewhere in Symfony 7 session code — is deliberately rejected here.
Solutions
- Unwrap the AbstractProxy and pass its underlying \SessionHandlerInterface implementation instead.
- Pass a plain \SessionHandlerInterface implementation (e.g. new \SessionHandler()) to the constructor.
- If the handler comes from Symfony DI, configure the service definition to expose the raw handler implementing \SessionHandlerInterface.
Example fix
// before
$storage->setSaveHandler($abstractProxy); // Symfony 7 AbstractProxy rejected
// after
$handler = method_exists($abstractProxy, 'getHandler') ? $abstractProxy->getHandler() : new \SessionHandler();
if ($handler instanceof \SessionHandlerInterface) {
$storage->setSaveHandler($handler);
} Defensive patterns
Strategy: type-guard
Validate before calling
if (!$handler instanceof \SessionHandlerInterface) {
// Symfony 7 may hand an AbstractProxy; unwrap it
$handler = $handler instanceof \Symfony\Component\HttpFoundation\Session\Storage\Proxy\AbstractProxy && method_exists($handler, 'getHandler')
? $handler->getHandler()
: new \SessionHandler();
}
$storage = new \Ratchet\Session\Storage\VirtualSessionStorageForSymfony7('sid', $handler); Type guard
function isRawSessionHandler($h): bool { return $h instanceof \SessionHandlerInterface; } Try / catch
try {
$storage->setSaveHandler($handler);
} catch (\InvalidArgumentException $e) {
$storage->setSaveHandler(new \SessionHandler());
} Prevention
- Never pass Symfony AbstractProxy instances to Ratchet's Symfony7 storage — pass raw handlers.
- After Symfony upgrades, re-check the type the framework supplies to setSaveHandler.
- Wrap DI services so the container exposes \SessionHandlerInterface implementations only.
When it happens
Trigger: Calling setSaveHandler (directly or via __construct) with an Symfony\Component\HttpFoundation\Session\Storage\Proxy\AbstractProxy instance, null, or any object not implementing \SessionHandlerInterface.
Common situations: Symfony 7 integrations where the framework hands an AbstractProxy to a session storage's setSaveHandler; code migrated from Symfony 6 passing proxy-wrapped handlers; DI misconfiguration supplying the wrong service.
Understand the failure class
Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.
Related errors
- Argument #4 ($serializer) expected…
- Handler must be instance of SessionHandlerInterface
- Handler must be instance of SessionHandlerInterface
- Unable to parse session serialize handler
- Can not change session name in VirtualProxy
AI-assisted analysis of ratchetphp/Ratchet@e621c6c40b (2026-09-16).
Data as JSON: /api/errors/c56b6334ecdf5422.
Report an issue: GitHub.
Appendix: source
Thrown at src/Ratchet/Session/Storage/VirtualSessionStorageForSymfony7.php:87
public function save(): void {
// get the data from the bags?
// serialize the data
// save the data using the saveHandler
// $this->saveHandler->write($this->saveHandler->getId(),
if (!$this->saveHandler->isWrapper() && !$this->getSaveHandler()->isSessionHandlerInterface()) {
$this->saveHandler->setActive(false);
}
$this->closed = true;
}
/**
* {@inheritdoc}
*/
public function setSaveHandler(AbstractProxy|\SessionHandlerInterface|null $saveHandler): void {
if (!($saveHandler instanceof \SessionHandlerInterface)) {
throw new \InvalidArgumentException('Handler must be instance of SessionHandlerInterface');
}
if (!($saveHandler instanceof VirtualProxy)) {
$saveHandler = new VirtualProxy($saveHandler);
}
$this->saveHandler = $saveHandler;
}
}
View on GitHub (pinned to e621c6c40b)