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
- Verify the browserWebSocketUrl is a genuine Chromium/Chrome devtools browser endpoint (ws://host:port/devtools/browser/<id>) from a recent Chrome/Chromium/Edge build
- Launch the browser with --remote-debugging-port and take the URL from http://host:port/json/version (webSocketDebuggerUrl) rather than hand-crafting it
- Upgrade karate to a version matching your browser's CDP protocol version
- 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
- Fetch the ws URL from http://host:port/json/version webSocketDebuggerUrl instead of constructing it
- Use a current Chrome/Chromium/Edge build for the driver
- Keep Karate and browser versions aligned
- Smoke-test the endpoint with curl http://host:port/json before running tests
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
- CDP connection failed readiness check
- CDP timeout for
- CDP error
- browser did not return a targetId for context
- not a devtools websocket url
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)