{"record":{"id":"5237579d7a7fbc8f","repo":"ratchetphp/Ratchet","slug":"handler-must-be-instance-of-sessionhandlerinterface-523757","errorCode":null,"errorMessage":"Handler must be instance of SessionHandlerInterface","messagePattern":"Handler must be instance of SessionHandlerInterface","errorType":"validation","errorClass":"InvalidArgumentException","httpStatus":null,"severity":"error","filePath":"src/Ratchet/Session/Storage/VirtualSessionStorageForSymfony6.php","lineNumber":86,"sourceCode":"    public function save() {\n        // get the data from the bags?\n        // serialize the data\n        // save the data using the saveHandler\n//        $this->saveHandler->write($this->saveHandler->getId(),\n\n        if (!$this->saveHandler->isWrapper() && !$this->getSaveHandler()->isSessionHandlerInterface()) {\n            $this->saveHandler->setActive(false);\n        }\n\n        $this->closed = true;\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public function setSaveHandler($saveHandler = null) {\n        if (!($saveHandler instanceof \\SessionHandlerInterface)) {\n            throw new \\InvalidArgumentException('Handler must be instance of SessionHandlerInterface');\n        }\n\n        if (!($saveHandler instanceof VirtualProxy)) {\n            $saveHandler = new VirtualProxy($saveHandler);\n        }\n\n        $this->saveHandler = $saveHandler;\n    }\n}\n","sourceCodeStart":68,"sourceCodeEnd":96,"githubUrl":"https://github.com/ratchetphp/Ratchet/blob/e621c6c40bf684bbbb877102416ad5303d05a9cc/src/Ratchet/Session/Storage/VirtualSessionStorageForSymfony6.php#L68-L96","documentation":"VirtualSessionStorageForSymfony6::setSaveHandler throws InvalidArgumentException when the supplied save handler does not implement \\SessionHandlerInterface. Like the base VirtualSessionStorage, it needs the interface so it can wrap the handler in VirtualProxy. The Symfony6 variant exists to satisfy Symfony 6 session storage signatures while keeping Ratchet's virtual session behavior.","triggerScenarios":"Constructing VirtualSessionStorageForSymfony6 (its constructor calls setSaveHandler) with null or a handler object lacking \\SessionHandlerInterface; calling setSaveHandler directly with such a value.","commonSituations":"Integrating Ratchet sessions into a Symfony 6 app and passing Symfony's own session storage/handler classes that do not implement the plain \\SessionHandlerInterface contract expected here; misconfiguring the session handler service.","solutions":["Pass an instance of \\SessionHandlerInterface (e.g. \\SessionHandler or a Symfony handler that implements the interface, such as NativeSessionHandler subclasses) to the constructor.","Verify the DI container wires a real \\SessionHandlerInterface implementation, not the storage wrapper itself.","Add the interface to a custom handler class and implement all required methods with correct signatures."],"exampleFix":"// before\nnew \\Ratchet\\Session\\Storage\\VirtualSessionStorageForSymfony6('sid'); // constructor given no handler\n// after\nnew \\Ratchet\\Session\\Storage\\VirtualSessionStorageForSymfony6('sid', new \\SessionHandler());","handlingStrategy":"type-guard","validationCode":"if (!$handler instanceof \\SessionHandlerInterface) {\n    throw new \\InvalidArgumentException('VirtualSessionStorageForSymfony6 requires \\SessionHandlerInterface');\n}\n$storage = new \\Ratchet\\Session\\Storage\\VirtualSessionStorageForSymfony6('sid', $handler);","typeGuard":"function isSymfony6CompatibleHandler($h): bool { return $h instanceof \\SessionHandlerInterface; }","tryCatchPattern":"try {\n    $storage = new \\Ratchet\\Session\\Storage\\VirtualSessionStorageForSymfony6('sid', $handler);\n} catch (\\InvalidArgumentException $e) {\n    $storage = new \\Ratchet\\Session\\Storage\\VirtualSessionStorageForSymfony6('sid', new \\SessionHandler());\n}","preventionTips":["In Symfony 6 wiring, bind the service id of a handler implementing \\SessionHandlerInterface, not the session storage.","Unit-test the constructor with the exact service your container resolves.","Handle AbstractProxy-wrapped handlers by unwrapping before passing."],"tags":["php","session","symfony","invalid-argument"],"backgroundTag":"invalid-argument-value","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"}