karatelabs/karate · error · DriverException

not a devtools websocket url

Error message

not a devtools websocket url: {browserWebSocketUrl}

What it means

pageWsUrlFrom derives a page WebSocket endpoint by rewriting the browser's /devtools/browser/<id> URL to /devtools/page/<targetId>. If the given URL does not contain '/devtools/', it is not a Chromium devtools browser endpoint and the rewrite is impossible, so this DriverException is thrown.

Solutions

  1. Use the exact webSocketDebuggerUrl reported by http://host:port/json/version (it always contains /devtools/browser/)
  2. If behind a proxy that rewrites paths, ensure the /devtools/ prefix is preserved end-to-end
  3. Validate the URL starts with ws(s)://host:port/devtools/browser/ before passing it to connectNewContext

Example fix

// before
String url = "ws://localhost:9222";
CdpDriver.connectNewContext(url, options);
// after
String url = "ws://localhost:9222/devtools/browser/" + browserId; // from /json/version
CdpDriver.connectNewContext(url, options);
Defensive patterns

Strategy: validation

Validate before calling

boolean ok = url.startsWith("ws://") || url.startsWith("wss://");
ok = ok && url.contains("/devtools/browser/");
if (!ok) throw new IllegalArgumentException("not a devtools browser websocket url: " + url);

Try / catch

try { return CdpDriver.connectNewContext(url, options); } catch (DriverException e) { if (e.getMessage().startsWith("not a devtools")) { url = fetchDevtoolsUrl(host, port); return CdpDriver.connectNewContext(url, options); } throw e; }

Prevention

When it happens

Trigger: Calling CdpDriver.connectNewContext (or anything that calls pageWsUrlFrom) with a browserWebSocketUrl lacking the '/devtools/' segment — e.g. ws://host:port alone, a raw socket path, or a vendor-specific endpoint format.

Common situations: Passing the raw debugging port URL (ws://localhost:9222) instead of the webSocketDebuggerUrl from /json/version; using a Playwright/Puppeteer-style browserWS endpoint whose path differs; typo in a configured driver URL.

Understand the failure class

Background: "Invalid URL" errors: why new URL(), URI.parse, and reqwest::Url reject your string — missing scheme, whitespace, and bad path format — this error's family across 39 libraries.

Related errors


AI-assisted analysis of karatelabs/karate@a22eb90246 (2026-09-12). Data as JSON: /api/errors/8c65dc27cac20d89. Report an issue: GitHub.

Appendix: source

Thrown at karate-core/src/main/java/io/karatelabs/driver/cdp/CdpDriver.java:584

                            .param("browserContextId", contextId).send();
                } catch (Exception ignored) {
                    logger.debug("could not dispose orphan browser context: {}", contextId);
                }
                throw e;
            }
        } finally {
            browser.close();
        }
    }

    /**
     * Derive the page endpoint for a target from a browser endpoint on the same browser.
     * ws://host:port/devtools/browser/&lt;id&gt; → ws://host:port/devtools/page/&lt;targetId&gt;
     */
    private static String pageWsUrlFrom(String browserWebSocketUrl, String targetId) {
        int index = browserWebSocketUrl.indexOf("/devtools/");
        if (index == -1) {
            throw new DriverException("not a devtools websocket url: " + browserWebSocketUrl);
        }
        return browserWebSocketUrl.substring(0, index) + "/devtools/page/" + targetId;
    }

    /**
     * Close all active drivers.
     */
    public static void closeAll() {
        ACTIVE.forEach(CdpDriver::quit);
    }

    private void initialize() {
        logger.debug("initializing CDP driver");

        // CRITICAL: Get main frame ID FIRST - needed by event handlers
        // This works without Page.enable and ensures handlers can filter by frame
        CdpResponse frameResponse = cdp.method("Page.getFrameTree").send();
        mainFrameId = frameResponse.getResult("frameTree.frame.id");

View on GitHub (pinned to a22eb90246)