karatelabs/karate · warning

Pool exhausted for scenario

Error message

Pool exhausted for scenario '{}', waiting for available driver... [{}]

What it means

PooledDriverProvider logs this warning when all drivers in the fixed-size pool are busy and a new scenario must wait up to 30 seconds for one to be released. If no driver is returned within the timeout, a RuntimeException ('Timeout waiting for available driver') is thrown. It signals that demand for browser drivers exceeds the configured pool size.

Solutions

  1. Increase the driver pool size (driver.poolSize / karate.pool config) to at least the parallel scenario count
  2. Fix scenarios that hang and hold drivers (add navigation timeouts, fail fast)
  3. Reduce parallelism (-Dkarate.options='... threads=...') to match pool size
  4. Check pool stats in the log ([{}]) to see how many drivers are created vs waiting

Example fix

// before
-Dkarate.options="-t @smoke threads=10"
// driver.poolSize defaults lower
// after
DriverOptions options = ...; options.setPoolSize(10);
// or set -Ddriver.poolSize=10 so each thread gets a slot
Defensive patterns

Strategy: validation

Validate before calling

// before the run: ensure pool >= threads
int threads = Integer.getInteger("karate.threads", 1);
int pool = Integer.getInteger("driver.poolSize", threads);
if (pool < threads) throw new IllegalStateException(
    "driver.poolSize (" + pool + ") must be >= parallel threads (" + threads + ")");

Try / catch

try {
    Driver d = provider.acquire(options, runtime);
} catch (RuntimeException e) {
    if (e.getMessage().contains("Timeout waiting for available driver")) {
        // retry once or fail the scenario fast
    }
}

Prevention

When it happens

Trigger: Running more concurrent scenarios than the configured karate driver pool size; a scenario leaking/not releasing drivers so acquire() calls waitForDriver() with every slot taken.

Common situations: CI parallel runs where parallel count exceeds poolSize; a stuck scenario holding a driver past 30s (hangs on navigation); forgetting to size the pool to match threads in karate.options.

Understand the failure class

Background: Request timed out: what client-side request timeouts mean across libraries (Request timed out, TIMED_OUT, APITimeoutError) — this error's family across 39 libraries.

Related errors


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

Appendix: source

Thrown at karate-core/src/main/java/io/karatelabs/driver/PooledDriverProvider.java:195

                return;
            }
            // Auto-detect pool size from Suite's threadCount
            if (poolSize < 1 && runtime.getFeatureRuntime() != null
                    && runtime.getFeatureRuntime().getSuite() != null) {
                poolSize = runtime.getFeatureRuntime().getSuite().threadCount;
                logger.info("Auto-detected pool size from Suite: {}", poolSize);
            }
            if (poolSize < 1) {
                poolSize = 1;  // Fallback
                logger.warn("Could not detect pool size, defaulting to 1");
            }
            availableDrivers = new ArrayBlockingQueue<>(poolSize);
        }
    }

    private Driver waitForDriver(Map<String, Object> config, ScenarioRuntime runtime) {
        String scenarioName = runtime.getScenario().getName();
        logger.warn("Pool exhausted for scenario '{}', waiting for available driver... [{}]",
                scenarioName, getStats());
        try {
            Driver driver = availableDrivers.poll(30, TimeUnit.SECONDS);
            if (driver == null) {
                throw new RuntimeException("Timeout waiting for available driver for scenario '"
                        + scenarioName + "' [" + getStats() + "]");
            }
            // If the driver is terminated OR fails reset/liveness, replace it.
            // Same rationale as takeHealthyFromPool — a poisoned driver must not be
            // handed out to the next scenario.
            if (driver.isTerminated()) {
                createdCount.decrementAndGet();
                driver = createDriver(config);
                createdCount.incrementAndGet();
                logger.info("Replaced terminated driver for scenario: {}", scenarioName);
            } else if (!resetDriver(driver)) {
                closeDriverQuietly(driver);
                createdCount.decrementAndGet();

View on GitHub (pinned to a22eb90246)