karatelabs/karate · error

chrome process died while waiting for page targets

Error message

chrome process died while waiting for page targets (exit code: {})

What it means

WARN log from CdpLauncher.waitForWebSocketUrl when the launched Chrome process exits while Karate is polling the DevTargets HTTP endpoint to discover the WebSocket debugger URL. The method returns null, which causes start() to fail launching the driver.

Solutions

  1. Match the exit code (logged) against Chrome startup failure docs; common codes indicate bad flags or missing deps.
  2. In Docker/root, add --no-sandbox (or run as non-root) via driver addOptions.
  3. Use a fresh, writable user-data-dir to avoid profile lock/corruption issues.
  4. Check the debugging port isn't occupied and the Chrome version is compatible with the Karate/CDP driver.
  5. Increase available memory in CI; Chrome often dies from OOM during startup.

Example fix

// before
karate.configure('driver', { type: 'chrome' });
// after (containerized / CI environment)
karate.configure('driver', {
  type: 'chrome',
  addOptions: ['--no-sandbox', '--disable-dev-shm-usage'],
  userDataDir: '/tmp/karate-chrome-profile'
});
Defensive patterns

Strategy: try-catch

Validate before calling

// pre-launch sanity checks in CI
assert new File("/dev/shm").getFreeSpace() > 256 * 1024 * 1024; // ample shm
// ensure debug port is free
try (var s = new java.net.ServerSocket(9222)) { /* free */ } catch (IOException e) { throw new IllegalStateException("port 9222 in use"); }

Try / catch

try {
    driver = Driver.start("chrome");
} catch (RuntimeException e) {
    // launcher returned null websocket url — chrome died at startup
    logger.error("chrome failed to start: {}", e.getMessage());
    throw new SkipException("browser unavailable", e);
}

Prevention

When it happens

Trigger: During startup, process.isAlive() becomes false while waiting for the page-targets list — Chrome crashed immediately after launch, failed to bind its debugging port, or was killed by the OS/CI.

Common situations: Missing --no-sandbox in root/Docker containers; Chrome version incompatibility with the CDP protocol; corrupted user-data-dir; port conflicts with an existing Chrome instance; OOM-kill in constrained CI memory.

Related errors


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

Appendix: source

Thrown at karate-core/src/main/java/io/karatelabs/driver/cdp/CdpLauncher.java:235

        HttpClient client = HttpClient.newBuilder()
                .connectTimeout(Duration.ofSeconds(5))
                .build();

        long startTime = System.nanoTime();
        long timeoutNanos = timeoutMs * 1_000_000L;
        String url = "http://" + host + ":" + port + "/json";
        int intervalMs = 250;
        int attemptCount = 0;

        // Use elapsed time instead of attempt count to handle variable request durations
        // Always make at least one attempt even if timeout is very small
        while (attemptCount == 0 || (System.nanoTime() - startTime) < timeoutNanos) {
            attemptCount++;

            // Check if process died
            if (process != null && !process.isAlive()) {
                int exitCode = process.getExitCode();
                logger.warn("chrome process died while waiting for page targets (exit code: {})", exitCode);
                return null;
            }

            try {
                HttpRequest request = HttpRequest.newBuilder()
                        .uri(URI.create(url))
                        .timeout(Duration.ofSeconds(5))
                        .GET()
                        .build();

                HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
                if (response.statusCode() == 200) {
                    List<Map<String, Object>> targets = (List<Map<String, Object>>) JSONValue.parse(response.body());
                    if (targets != null && !targets.isEmpty()) {
                        // Look for a valid page target (same logic as v1)
                        for (Map<String, Object> target : targets) {
                            String targetUrl = (String) target.get("url");
                            String targetType = (String) target.get("type");

View on GitHub (pinned to a22eb90246)