{"record":{"id":"07f20b2cbe440cb7","repo":"karatelabs/karate","slug":"cdp-error-message","errorCode":null,"errorMessage":"CDP error: {message}","messagePattern":"CDP error: (.+?)","errorType":"exception","errorClass":"RuntimeException","httpStatus":null,"severity":"error","filePath":"karate-core/src/main/java/io/karatelabs/driver/cdp/CdpClient.java","lineNumber":275,"sourceCode":"    }\n\n    // Send methods\n\n    /**\n     * Blocking send with response.\n     */\n    CdpResponse send(CdpMessage message) {\n        try {\n            return sendAsync(message).join();\n        } catch (CompletionException e) {\n            Throwable cause = e.getCause();\n            if (cause instanceof TimeoutException) {\n                throw new RuntimeException(\"CDP timeout for: \" + message.getMethod());\n            }\n            if (cause instanceof RuntimeException) {\n                throw (RuntimeException) cause;\n            }\n            throw new RuntimeException(\"CDP error: \" + cause.getMessage(), cause);\n        }\n    }\n\n    /**\n     * Async send with response tracking.\n     */\n    CompletableFuture<CdpResponse> sendAsync(CdpMessage message) {\n        // Fail fast if connection is closed\n        if (!ws.isOpen()) {\n            return CompletableFuture.failedFuture(\n                    new WsException(WsException.Type.CONNECTION_CLOSED, \"websocket not open\"));\n        }\n\n        CompletableFuture<CdpResponse> future = new CompletableFuture<>();\n        int messageId = message.getId();\n        pending.put(messageId, new PendingRequest(future, message.getMethod()));\n\n        String json = message.toJson();","sourceCodeStart":257,"sourceCodeEnd":293,"githubUrl":"https://github.com/karatelabs/karate/blob/a22eb90246d958d15a47bf436693d0121ad2812d/karate-core/src/main/java/io/karatelabs/driver/cdp/CdpClient.java#L257-L293","documentation":"CdpClient.send() rethrows non-timeout failures from the async send: if the cause is a RuntimeException it propagates directly; otherwise it is wrapped as 'CDP error: <cause message>'. This is the generic wrapper for any CDP command failure that is not a timeout or already a RuntimeException.","triggerScenarios":"Underlying sendAsync fails with a checked/non-runtime cause (IO errors, closed websocket wrapped in CompletionException); any unexpected completion exception from the CDP future chain.","commonSituations":"Websocket closed mid-command (browser crashed or exited); IO errors on the DevTools socket in flaky CI environments; internal client failures surfacing through the CompletionException unwrap path.","solutions":["Inspect the chained cause (getCause()) for the root problem — socket closed, browser crashed, etc.","Verify the browser is still running; relaunch the driver if the session died","Check CI stability: resource limits (memory) that kill the browser mid-run","Retry flaky steps; wrap driver interactions with retry for transient socket failures"],"exampleFix":"// before\nCdpResponse resp = client.method(\"Page.navigate\").param(\"url\", url).send(); // browser died -> 'CDP error'\n// after: guard with liveness check\nif (karate.driver.isTerminated() == false) {\n    CdpResponse resp = client.method(\"Page.navigate\").param(\"url\", url).send();\n} else {\n    karate.driver = karate.driverManager.restart();\n}","handlingStrategy":"try-catch","validationCode":"if (driver.isTerminated()) { driver = restartDriver(); } // skip send on dead session","typeGuard":"null","tryCatchPattern":"try { CdpResponse r = client.method(m).send(); }\ncatch (RuntimeException e) {\n    if (e.getMessage() != null && e.getMessage().startsWith(\"CDP error:\")) {\n        logger.error(\"CDP root cause:\", e.getCause());\n        throw new DriverException(\"browser session unhealthy\", e.getCause());\n    }\n    throw e;\n}","preventionTips":["Inspect the chained cause for the true failure","Relaunch drivers after browser crashes instead of reusing them","Harden CI against browser OOM kills (memory limits)","Retry transient socket failures"],"tags":["cdp","websocket","unexpected-failure"],"backgroundTag":"api-error-response","analyzedSha":"a22eb90246d958d15a47bf436693d0121ad2812d","analyzedAt":"2026-09-12T09:01:00.220Z","contentChangedAt":"2026-09-12T09:01:00.220Z","schemaVersion":2},"datasetVersion":"2026-09-16T19:17:19.609Z"}