{"record":{"id":"853dc0baba39ada7","repo":"karatelabs/karate","slug":"element-not-found-after-retrycount-retries-locator","errorCode":null,"errorMessage":"element not found after ${retryCount} retries: ${locator} | ${driverState}","messagePattern":"element not found after (.+?) retries: (.+?) \\| (.+?)","errorType":"exception","errorClass":"DriverException","httpStatus":null,"severity":"error","filePath":"karate-core/src/main/java/io/karatelabs/driver/cdp/CdpDriver.java","lineNumber":3221,"sourceCode":"    @SuppressWarnings(\"unchecked\")\n    public List<Object> scriptAll(String locator, Object expression) {\n        retryIfNeeded(locator);\n        String js = Locators.scriptAllSelector(locator, expression);\n        return (List<Object>) script(js);\n    }\n\n    // ========== Auto-Wait Helper ==========\n\n    /**\n     * Auto-wait for element to exist before operations.\n     * Uses retryCount and retryInterval from options.\n     * This is called automatically before element operations to reduce flaky tests.\n     */\n    private void retryIfNeeded(String locator) {\n        boolean found = retry(\"element: \" + locator, () -> exists(locator));\n        if (!found) {\n            // Include driver state in exception for better diagnostics\n            throw new DriverException(\"element not found after \" + options.getRetryCount() +\n                    \" retries: \" + locator + \" | \" + getDriverState());\n        }\n    }\n\n    /**\n     * Re-resolve attempts for an element that vanished between the existence check and\n     * the action eval. Small on purpose: each attempt already carries a full\n     * {@link #retryIfNeeded} poll, and a locator that keeps vanishing is a genuinely\n     * unstable page, not a transient worth papering over.\n     */\n    private static final int ELEMENT_ACTION_ATTEMPTS = 3;\n\n    /**\n     * Wait for {@code locator} to exist, then run an action script that re-resolves it\n     * inside the page, retrying if it vanished in between.\n     * <p>\n     * The locator is resolved twice — once here by {@link #retryIfNeeded} (existence)\n     * and again by the action JS itself — so a document that swaps between the two evals","sourceCodeStart":3203,"sourceCodeEnd":3239,"githubUrl":"https://github.com/karatelabs/karate/blob/a22eb90246d958d15a47bf436693d0121ad2812d/karate-core/src/main/java/io/karatelabs/driver/cdp/CdpDriver.java#L3203-L3239","documentation":"Before element operations, CdpDriver.retryIfNeeded() polls exists(locator) using the configured retry count and interval. If the element still does not exist after options.getRetryCount() attempts, it throws with the locator and a getDriverState() snapshot for diagnostics.","triggerScenarios":"Any element API (click, input, text, inputFile, select...) called with a locator that never matches during the retry window: wrong selector, element in an unswitched frame, element removed before the call, or retry budget too short for slow pages.","commonSituations":"Slow CI machines exceeding the default retry timeout; dynamic content rendered only after an async API call; iframe not switched; typo or changed id/class after an app update; SPA navigation clearing the element between steps.","solutions":["Verify the selector in the browser DevTools against the page state at that step.","Increase options.retryCount / retryInterval in driver config for slow environments.","Wait for prerequisite actions/navigation before the element call, or use driver.waitFor(locator, timeout) for an explicit budget.","Switch to the correct frame first if the element lives in an iframe; inspect the driver-state suffix in the message for the current URL/frame."],"exampleFix":"// before\nDriverOptions options = new DriverOptions(); // default retries too low on slow CI\n// after\noptions.setRetryCount(20);\noptions.setRetryInterval(500);\ndriver.waitFor('#slow-widget', Duration.ofSeconds(10));\ndriver.click('#slow-widget');","handlingStrategy":"retry","validationCode":"// pre-check existence with your own budget before element ops\nlong deadline = System.currentTimeMillis() + 10_000;\nwhile (!driver.exists(locator) && System.currentTimeMillis() < deadline) sleep(250);\nif (!driver.exists(locator)) throw new IllegalStateException(\"not present: \" + locator);","typeGuard":null,"tryCatchPattern":"try {\n    driver.click(locator);\n} catch (Exception e) {\n    if (e.getMessage().contains(\"element not found after\")) {\n        // driver state in message shows current URL/frame for triage\n        throw new AssertionError(\"element never appeared: \" + e.getMessage(), e);\n    } else throw e;\n}","preventionTips":["Raise retryCount/retryInterval for slow environments.","waitFor elements explicitly instead of relying on implicit retries.","Switch frames before interacting with iframe content.","Keep selectors updated with the app's stable test ids."],"tags":["driver","element-not-found","retry","timeout","locator"],"backgroundTag":"request-timeout","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"}