karatelabs/karate · warning

driver.stop=false — leaving browser running, scenario will…

Error message

driver.stop=false — leaving browser running, scenario will not close it: {}

What it means

When tearing down a scenario that has a driver, Karate checks `driver.getOptions().isStop()`. If stop is false (from `configure driver = { stop: false }`), Karate deliberately leaves the browser running, drops its driver reference, and logs this warning. The scenario will not close the browser, and one pool slot's accounting is lost.

Solutions

  1. Remove `stop:false` so normal quit/release teardown resumes
  2. Manually kill leftover browser/driver processes after debug sessions
  3. Only use stop:false in throwaway local debug runs, never on shared CI nodes
  4. Restart the driver pool / JVM if pool accounting drifts

Example fix

// before
configure driver = { type: 'chromedriver', stop: false }
// after
configure driver = { type: 'chromedriver' }
Defensive patterns

Strategy: fallback

Validate before calling

// Guard configs that may carry stop:false:
if (karate.get('driverConfig') && karate.get('driverConfig').stop === false) { karate.log('browser will leak; debug only'); }

Prevention

When it happens

Trigger: Scenario end (or driver release path) reached while the driver options carry `stop=false`, e.g. after `configure driver = { stop: false }` was set during the scenario.

Common situations: Post-failure DOM inspection sessions; leaked browsers accumulating after debug runs; confusing 'browser still open' states on CI agents.

Related errors


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

Appendix: source

Thrown at karate-core/src/main/java/io/karatelabs/core/ScenarioRuntime.java:2364

     */
    private void closeDriver() {
        if (driver == null) {
            return;
        }

        // Don't close inherited driver - the owner (caller scenario) will close it
        if (driverInherited) {
            driver = null;
            return;
        }

        // configure driver = { stop: false } — leave the browser running for DOM
        // inspection. Skips both direct quit() and the pool's release(). Note that
        // a leaked driver here loses one slot from the pool's accounting; that's
        // accepted because stop:false is a single-scenario debug flag.
        try {
            if (!driver.getOptions().isStop()) {
                logger.warn("driver.stop=false — leaving browser running, scenario will not close it: {}",
                        scenario.getName());
                driver = null;
                return;
            }
        } catch (Exception e) {
            logger.debug("could not read driver options for stop check: {}", e.getMessage());
        }

        // Shared-scope called feature: propagate the driver up to the caller scenario
        // immediately so sibling scenarios in this same called feature can inherit it
        // via the normal inheritDriverFromCaller path. Without this, scenario N+1 in a
        // multi-scenario called feature can't see scenario N's driver — it falls
        // through to PooledDriverProvider.acquire() and deadlocks if the pool is full.
        if (featureRuntime != null && featureRuntime.isSharedScope()
                && featureRuntime.getCallerScenario() != null) {
            featureRuntime.getCallerScenario().setDriverFromCallee(this);
            driver = null;
            return;

View on GitHub (pinned to a22eb90246)