{"record":{"id":"11f6ce8b0b8ad55c","repo":"SeleniumHQ/selenium","slug":"cdp-devtools-module-not-loaded-call-import-devtoo","errorCode":null,"errorMessage":"CDP devtools module not loaded. Call import_devtools() first.","messagePattern":"CDP devtools module not loaded\\. Call import_devtools\\(\\) first\\.","errorType":"exception","errorClass":"RuntimeError","httpStatus":null,"severity":"critical","filePath":"py/private/cdp.py","lineNumber":314,"sourceCode":"            # Otherwise, continue the generator to parse the JSON result\n            # into a CDP object.\n            try:\n                _ = cmd.send(data[\"result\"])\n                raise InternalError(\"The command's generator function did not exit when expected!\")\n            except StopIteration as exit:\n                return_ = exit.value\n            self.inflight_result[cmd_id] = return_\n        event.set()\n\n    def _handle_event(self, data: dict):\n        \"\"\"Handle an event.\n\n        Args:\n            data: event as a JSON dictionary\n        \"\"\"\n        global devtools\n        if devtools is None:\n            raise RuntimeError(\"CDP devtools module not loaded. Call import_devtools() first.\")\n        event = devtools.util.parse_json_event(data)\n        logger.debug(\"Received event: %s\", event)\n        to_remove = set()\n        for sender in self.channels[type(event)]:\n            try:\n                sender.send_nowait(event)\n            except trio.WouldBlock:\n                logger.error('Unable to send event \"%r\" due to full channel %s', event, sender)\n            except trio.BrokenResourceError:\n                to_remove.add(sender)\n        if to_remove:\n            self.channels[type(event)] -= to_remove\n\n\nclass CdpSession(CdpBase):\n    \"\"\"Contains the state for a CDP session.\n\n    Generally you should not instantiate this object yourself; you should call","sourceCodeStart":296,"sourceCodeEnd":332,"githubUrl":"https://github.com/SeleniumHQ/selenium/blob/aa36b38e696a0909e973bdf5e2f9031ffe842c4b/py/private/cdp.py#L296-L332","documentation":"Raised as a RuntimeError by CdpConnection._handle_event() when the global `devtools` module is None at the time an event message is received from the WebSocket. The devtools module (generated CDP type definitions) must be loaded via import_devtools() before any event can be parsed. The _handle_event method calls devtools.util.parse_json_event(data), so it requires devtools to be initialized. This fires during background event dispatch, not at call time.","triggerScenarios":"A CDP event arrives on the WebSocket (dispatched by the reader task to _handle_event) before import_devtools() has been called. The global `devtools` variable is None, so event parsing cannot proceed. This is a race or initialization-order error.","commonSituations":"Forgetting to call import_devtools() (typically auto-called during connection setup but can be missed in custom setups); a timing issue where events arrive before the devtools import completes; manually constructing a CdpConnection without the standard initialization path.","solutions":["Call import_devtools() early in your setup, before creating or using any CDP connection. It is normally called automatically by Connection.create().","Ensure you are using the standard connection creation path (Connection.create) which calls import_devtools() rather than constructing CdpConnection directly.","If customizing initialization, call import_devtools() as the first step before any WebSocket communication begins."],"exampleFix":"# before\n# Connection created without import_devtools()\nconn = CdpConnection(ws)\n# ... events arrive, _handle_event raises RuntimeError\n\n# after\nfrom selenium.webdriver.common.bidi.cdp import import_devtools\nimport_devtools()\nconn = await Connection.create(url)  # standard path\n# events now parse correctly","handlingStrategy":"validation","validationCode":"from selenium.webdriver.common.bidi.cdp import devtools, import_devtools\nif devtools is None:\n    import_devtools()","typeGuard":null,"tryCatchPattern":"try:\n    await conn.do_work()\nexcept RuntimeError as e:\n    if 'devtools module not loaded' in str(e):\n        import_devtools()\n        await conn.do_work()\n    else:\n        raise","preventionTips":["Call import_devtools() before any CDP connection setup.","Use the standard Connection.create() path which handles initialization.","Verify import_devtools() succeeds without silent failure."],"tags":["python","cdp","devtools","initialization","trio"],"backgroundTag":null,"analyzedSha":"aa36b38e696a0909e973bdf5e2f9031ffe842c4b","analyzedAt":"2026-08-14T02:32:32.244Z","schemaVersion":2},"datasetVersion":"2026-08-14T05:17:29.042Z"}