karatelabs/karate · warning

failed to create blank tab, quitting driver

Error message

failed to create blank tab, quitting driver

What it means

During close(), the driver first switches to a newly created blank tab (Target.createTarget with about:blank) so remaining pages can be torn down safely. If createTarget returns no targetId, the driver logs this warning and falls back to quit() — killing the whole browser instead of the graceful per-tab close. This means graceful close degraded to a hard shutdown.

Solutions

  1. Nothing to fix if the browser is already gone — quit() is the correct fallback; check earlier logs for the root cause of the browser death.
  2. Avoid double-close: guard with driver.isTerminated() or ensure quit() is called only once in teardown.
  3. If the browser crashes often, check for OOM in CI, mismatched browser/Driver versions, or a corrupted user-data-dir.
  4. Update Chrome/Chromium to a version compatible with the Karate release.

Example fix

// before
@After public void teardown() { driver.close(); driver.quit(); }
// after
@After public void teardown() { if (!driver.isTerminated()) { driver.quit(); } }
Defensive patterns

Strategy: fallback

Validate before calling

if (driver.isTerminated()) { return; } // skip teardown if already dead

Try / catch

try {
    driver.close();
} catch (RuntimeException e) {
    // close() itself falls back to quit(); swallow secondary teardown errors
    logger.warn("teardown issue ignored: {}", e.getMessage());
}

Prevention

When it happens

Trigger: close() called while the browser process is dying/crashed, CDP browser-level websocket already broken, or a browser build/version where Target.createTarget fails (e.g. too many targets, profile locked).

Common situations: Calling driver.quit()/close() twice, browser crashed earlier in the test, killing the browser externally (taskkill/OOM) before close(), or Chromium builds with restrictive target limits.

Related errors


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

Appendix: source

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

        String nextTarget = null;
        for (String pageId : allPages) {
            if (!pageId.equals(targetToClose)) {
                nextTarget = pageId;
                break;
            }
        }
        logger.debug("close() - switching to: {}", nextTarget);

        if (nextTarget == null) {
            // Last tab - create a blank page to keep browser alive
            // Uses browserMethod() because Target.createTarget is browser-level
            CdpResponse response = cdp.browserMethod("Target.createTarget")
                    .param("url", "about:blank")
                    .send();
            nextTarget = response.getResult("targetId");
            logger.debug("close() - created blank tab: {}", nextTarget);
            if (nextTarget == null) {
                logger.warn("failed to create blank tab, quitting driver");
                quit();
                return;
            }
        }

        // Switch to another tab first (establishes new session)
        activateTarget(nextTarget);
        logger.debug("close() - switched to: {}, now closing: {}", nextTarget, targetToClose);

        // Register the removal future BEFORE sending closeTarget, then close.
        // Target.closeTarget returns before the target is fully removed, so callers
        // that enumerate tabs right after close() would still see the old one.
        CompletableFuture<Void> removed = new CompletableFuture<>();
        pendingTargetRemovals.put(targetToClose, removed);
        try {
            cdp.browserMethod("Target.closeTarget")
                    .param("targetId", targetToClose)
                    .send();

View on GitHub (pinned to a22eb90246)