{"record":{"id":"d9552fe698f8aaad","repo":"karatelabs/karate","slug":"pool-full-closing-excess-driver","errorCode":null,"errorMessage":"Pool full, closing excess driver","messagePattern":"Pool full, closing excess driver","errorType":"console","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"karate-core/src/main/java/io/karatelabs/driver/PooledDriverProvider.java","lineNumber":284,"sourceCode":"        // scenario that acquires this driver.\n        //\n        // Why this matters (context for future maintainers): intercept.feature's\n        // wildcard-pattern scenario set Fetch.enable via driver.intercept() and never\n        // called stopIntercept. The driver went back to the pool with Fetch.enable\n        // still active and a stale JS InterceptHandler from a destroyed scenario.\n        // Every subsequent Page.navigate on that driver paused ALL subresource\n        // requests through our onRequestPaused event handler, which runs synchronously\n        // on the CDP websocket dispatch thread. A heavy page (HTML + CSS + JS + etc)\n        // could saturate that thread, queueing the Page.navigate command response\n        // behind the Fetch event backlog. The 30s CDP wall-clock timeout then fired\n        // before the response was dequeued → \"CDP timeout for: Page.navigate\".\n        cleanScenarioState(driver);\n\n        // Return to pool\n        boolean offered = availableDrivers.offer(driver);\n        if (!offered) {\n            // Pool full (shouldn't happen with correct sizing)\n            logger.warn(\"Pool full, closing excess driver\");\n            closeDriverQuietly(driver);\n            createdCount.decrementAndGet();\n        } else {\n            logger.debug(\"Returned driver to pool for scenario: {}\", runtime.getScenario().getName());\n        }\n    }\n\n    /**\n     * Tear down scenario-scoped driver state at owner-scenario exit. Called from\n     * {@link #release} before the driver is offered back to the pool.\n     * <p>\n     * Only state that belongs to the scenario's scope should be cleaned here —\n     * NOT cookies or page state, those belong in {@link #resetDriver} at acquire\n     * time (per-scenario setup vs per-scenario teardown).\n     * </p>\n     * <p>\n     * Subclasses overriding this should call {@code super.cleanScenarioState(driver)}\n     * to preserve intercept/dialog teardown.","sourceCodeStart":266,"sourceCodeEnd":302,"githubUrl":"https://github.com/karatelabs/karate/blob/a22eb90246d958d15a47bf436693d0121ad2812d/karate-core/src/main/java/io/karatelabs/driver/PooledDriverProvider.java#L266-L302","documentation":"On release(), the driver is offered back to the ArrayBlockingQueue of available drivers. If the queue is already full (offered == false), the excess driver is closed quietly and createdCount is decremented. The code notes this 'shouldn't happen with correct sizing', so it usually indicates a bookkeeping bug or duplicate release.","triggerScenarios":"Calling release() (or acquire/release lifecycle) more times than the pool expects, or pool size shrunk at runtime so queue capacity < outstanding drivers.","commonSituations":"A scenario runtime released twice on error paths; misconfigured poolSize smaller than number of drivers created earlier in the JVM; mixed use of pooled and non-pooled providers.","solutions":["Ensure each acquired driver is released exactly once (check for duplicate release in error/teardown paths)","Keep poolSize stable for the JVM lifetime; do not shrink queue capacity after drivers are created","Check getStats()/createdCount logs to spot leaked or double-released drivers"],"exampleFix":null,"handlingStrategy":"validation","validationCode":"// track acquire/release pairing in your harness\nSet<Driver> outstanding = ConcurrentHashMap.newKeySet();\n// on acquire: outstanding.add(d); on release: if (!outstanding.remove(d)) log.warn(\"double release\");","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Release each driver exactly once; centralize teardown","Do not shrink poolSize after drivers are created","Monitor getStats()/createdCount for drift"],"tags":["driver-pool","resource-leak","concurrency","invariant"],"backgroundTag":"internal-invariant-violation","analyzedSha":"a22eb90246d958d15a47bf436693d0121ad2812d","analyzedAt":"2026-09-12T09:01:00.220Z","contentChangedAt":"2026-09-12T09:01:00.220Z","schemaVersion":2},"datasetVersion":"2026-09-16T19:17:19.609Z"}