{"record":{"id":"5b9c00228c7e75fb","repo":"github/copilot-sdk","slug":"websocket-forwarding-requires-the-websockets-pac","errorCode":null,"errorMessage":"WebSocket forwarding requires the 'websockets' package. Install it or override open_websocket().","messagePattern":"WebSocket forwarding requires the 'websockets' package\\. Install it or override open_websocket\\(\\)\\.","errorType":"exception","errorClass":"RuntimeError","httpStatus":null,"severity":"error","filePath":"python/copilot/copilot_request_handler.py","lineNumber":195,"sourceCode":"    \"\"\"Default pass-through WebSocket handler backed by the ``websockets`` library.\"\"\"\n\n    def __init__(self, context: CopilotRequestContext) -> None:\n        super().__init__(context)\n        self._upstream: Any | None = None\n        self._receive_task: asyncio.Task[None] | None = None\n\n    async def send_request_message(self, data: str | bytes) -> None:\n        if self._upstream is None:\n            return\n        await self._upstream.send(data)\n\n    async def open(self) -> None:\n        if self._upstream is not None:\n            return\n        try:\n            import websockets\n        except ImportError as exc:  # pragma: no cover - optional dependency\n            raise RuntimeError(\n                \"WebSocket forwarding requires the 'websockets' package. \"\n                \"Install it or override open_websocket().\"\n            ) from exc\n\n        headers = [\n            (name, value)\n            for name, values in self.context.headers.items()\n            if name.lower() not in _FORBIDDEN_REQUEST_HEADERS\n            for value in (values or [])\n        ]\n        self._upstream = await websockets.connect(self.context.url, additional_headers=headers)\n        self._receive_task = asyncio.create_task(self._receive_loop())\n\n    async def _receive_loop(self) -> None:\n        try:\n            async for message in self._upstream:  # type: ignore[union-attr]\n                await self.send_response_message(message)\n            await self.close(CopilotWebSocketCloseStatus.normal_closure())","sourceCodeStart":177,"sourceCodeEnd":213,"githubUrl":"https://github.com/github/copilot-sdk/blob/cd8cf15dc3f9e762615790aaed0a771a0f392755/python/copilot/copilot_request_handler.py#L177-L213","documentation":"The WebSocket forwarding path needs the third-party 'websockets' package to establish the upstream connection. It is an optional dependency; when the import fails, open() raises RuntimeError telling the user to install it or override open_websocket() with a custom implementation.","triggerScenarios":"Calling open() (directly or via the request lifecycle) on CopilotWebSocketRequestHandler without overriding open_websocket(), in an environment where 'websockets' is not installed.","commonSituations":"Minimal/production installs that omitted the websocket extra, Docker images with only core deps, or environments that use a different websocket library.","solutions":["Install the optional dependency: pip install 'websockets' (or the package's websocket extra)","Subclass and override open_websocket() to supply your own upstream connection implementation","Pin the dependency in your requirements/Dockerfile so deployment images always include it","Check import websockets in a startup smoke test to fail at boot, not per-request"],"exampleFix":"// before\nhandler = CopilotWebSocketRequestHandler(context)\nawait handler.open()  # RuntimeError: websockets missing\n// after\n# pip install websockets\nawait handler.open()","handlingStrategy":"fallback","validationCode":"try:\n    import websockets\n    HAS_WEBSOCKETS = True\nexcept ImportError:\n    HAS_WEBSOCKETS = False","typeGuard":"def websockets_available() -> bool:\n    try:\n        import websockets  # noqa: F401\n        return True\n    except ImportError:\n        return False","tryCatchPattern":"try:\n    await handler.open()\nexcept RuntimeError as e:\n    if \"websockets\" in str(e):\n        handler = CustomHandlerWithOwnWebSocket(context)\n        await handler.open()\n    else:\n        raise","preventionTips":["Install the websocket extra: pip install 'websockets'","Pin 'websockets' in requirements/Dockerfile","Override open_websocket() when using a custom websocket stack","Run an import smoke test at application startup"],"tags":["websocket","dependency","optional-dependency","installation"],"backgroundTag":"missing-optional-dependency","analyzedSha":"cd8cf15dc3f9e762615790aaed0a771a0f392755","analyzedAt":"2026-09-09T18:32:31.973Z","contentChangedAt":"2026-09-09T18:32:31.973Z","schemaVersion":2},"datasetVersion":"2026-09-16T04:17:20.429Z"}