karatelabs/karate · error · DriverException

browser did not return a browserContextId

Error message

browser did not return a browserContextId: {browserWebSocketUrl}

What it means

When Karate attaches to an already-running browser via its WebSocket URL, it first asks the browser to create a new incognito-like browser context (Target.createBrowserContext). If the CDP response contains no browserContextId, Karate cannot proceed to create a target/page inside it, so it throws this DriverException. It indicates the browser responded but not with the expected CDP payload.

Solutions

  1. Verify the browserWebSocketUrl is a genuine Chromium/Chrome devtools browser endpoint (ws://host:port/devtools/browser/<id>) from a recent Chrome/Chromium/Edge build
  2. Launch the browser with --remote-debugging-port and take the URL from http://host:port/json/version (webSocketDebuggerUrl) rather than hand-crafting it
  3. Upgrade karate to a version matching your browser's CDP protocol version
  4. Capture CDP traffic (e.g. with a logging proxy) to inspect the Target.createBrowserContext response for a missing browserContextId

Example fix

// before
CdpDriver.connectNewContext("ws://localhost:9222/devtools/browser/guess", options);
// after
String wsUrl = new Json(IoUtils.fromCdpUrl("localhost", 9222)).get("webSocketDebuggerUrl");
CdpDriver.connectNewContext(wsUrl, options);
Defensive patterns

Strategy: validation

Validate before calling

if (!browserWebSocketUrl.matches("ws(s)?://[^/]+/devtools/browser/.+")) throw new IllegalArgumentException("expected devtools browser ws url, got: " + browserWebSocketUrl);

Try / catch

try { driver = CdpDriver.connectNewContext(wsUrl, options); } catch (DriverException e) { if (e.getMessage().contains("browserContextId")) { /* fall back to plain connect or restart browser */ } else throw e; }

Prevention

When it happens

Trigger: Calling CdpDriver.connectNewContext(browserWebSocketUrl, options) against a browser whose response to Target.createBrowserContext lacks a browserContextId — typically a non-Chrome/CDP-compatible endpoint, a proxy mangling the response, or a browser whose CDP protocol version differs from what Karate expects.

Common situations: Pointing Karate at a WebSocket URL that is not really a Chromium devtools endpoint (e.g. an Electron app, old Chromium build, or a CDP-proxy like chrome-remote-interface relays); browser upgrades changing CDP response shapes; connecting to a websocket that speaks a similar but not identical protocol.

Understand the failure class

Background: "invalid response format", "malformed payload", "missing data field": when an API returns 200 but the response shape is wrong — this error's family across 23 libraries.

Related errors


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

Appendix: source

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

     * cookies of every other scenario running concurrently in that context. Per-tab
     * clearing cannot fix that; there is only one jar to clear. A per-driver context
     * gives each driver its own jar, so the reset only ever affects its own scenario.
     * </p>
     * <p>
     * The returned driver owns the context and disposes it (closing its tab with it) on
     * {@link #quit()}.
     * </p>
     *
     * @param browserWebSocketUrl a BROWSER-level endpoint (ws://host:port/devtools/browser/...),
     *                            not a page endpoint — see /json/version
     */
    public static CdpDriver connectNewContext(String browserWebSocketUrl, CdpDriverOptions options) {
        CdpClient browser = CdpClient.connect(browserWebSocketUrl, options.getTimeoutDuration());
        try {
            String contextId = browser.browserMethod("Target.createBrowserContext")
                    .send().getResultAsString("browserContextId");
            if (contextId == null) {
                throw new DriverException("browser did not return a browserContextId: " + browserWebSocketUrl);
            }
            try {
                String targetId = browser.browserMethod("Target.createTarget")
                        .param("url", "about:blank")
                        .param("browserContextId", contextId)
                        .send().getResultAsString("targetId");
                if (targetId == null) {
                    throw new DriverException("browser did not return a targetId for context: " + contextId);
                }
                CdpDriver driver = new CdpDriver(pageWsUrlFrom(browserWebSocketUrl, targetId), options);
                driver.ownedBrowserContextId = contextId;
                driver.browserWebSocketUrl = browserWebSocketUrl;
                logger.debug("created driver in browser context {} target {}", contextId, targetId);
                return driver;
            } catch (RuntimeException e) {
                // Never leave an orphan context behind on a half-built driver — it would
                // pin its storage partition for the life of the browser.
                try {

View on GitHub (pinned to a22eb90246)