{"record":{"id":"c7ae3d152a0cc3df","repo":"karatelabs/karate","slug":"locator-failed-twice-locator","errorCode":null,"errorMessage":"locator failed twice: ${locator}","messagePattern":"locator failed twice: (.+?)","errorType":"exception","errorClass":"DriverException","httpStatus":null,"severity":"error","filePath":"karate-core/src/main/java/io/karatelabs/driver/w3c/W3cDriver.java","lineNumber":1047,"sourceCode":"        // v1 pattern: single retry on locator failure — handles transient DOM changes\n        String js = \"return \" + Locators.selector(locator);\n        try {\n            Object result = session.executeScript(js);\n            if (W3cSession.isElementReference(result)) {\n                return W3cSession.elementIdFrom(result);\n            }\n        } catch (Exception e) {\n            logger.warn(\"locator failed, will retry once: {}\", e.getMessage());\n        }\n        // Single retry after sleep\n        sleep(options.getRetryInterval());\n        try {\n            Object result = session.executeScript(js);\n            if (W3cSession.isElementReference(result)) {\n                return W3cSession.elementIdFrom(result);\n            }\n        } catch (Exception e2) {\n            throw new DriverException(\"locator failed twice: \" + locator, e2);\n        }\n        throw new DriverException(\"Element not found: \" + locator);\n    }\n\n    /**\n     * Inject the Karate JS runtime (__kjs) into the browser if not already present.\n     * Same pattern as CdpDriver — loads driver.js from classpath resources.\n     * Provides wildcard locator resolution, shadow DOM traversal, and shared utilities.\n     */\n    private void ensureKjsRuntime() {\n        try {\n            // Guard on __kjs.resolve (the wildcard resolver), not merely __kjs — a co-installed\n            // helper may seed a partial window.__kjs without it; driver.js extends, never clobbers.\n            Object exists = session.executeScript(\n                    \"return typeof window.__kjs !== 'undefined' && typeof window.__kjs.resolve === 'function'\");\n            if (!Boolean.TRUE.equals(exists)) {\n                session.executeScript(DRIVER_JS);\n                logger.debug(\"Injected __kjs runtime into browser\");","sourceCodeStart":1029,"sourceCodeEnd":1065,"githubUrl":"https://github.com/karatelabs/karate/blob/a22eb90246d958d15a47bf436693d0121ad2812d/karate-core/src/main/java/io/karatelabs/driver/w3c/W3cDriver.java#L1029-L1065","documentation":"In W3cDriver's locator resolution, when the first (and retry) attempt to find the element via injected JavaScript fails with an exception, the driver wraps the second failure in a DriverException 'locator failed twice: <locator>' preserving the cause. It indicates the locator lookup script itself errored twice, not merely that the element was absent.","triggerScenarios":"Calling find/locator APIs (driver.locate, waitFor, click, input on a stale/invalid locator string) where executeScript of the locator JS throws on both attempts — e.g. malformed locator syntax, the __kjs runtime not injected, or a navigation/page context invalidation mid-lookup.","commonSituations":"Typo'd or unsupported wildcard locator syntax; page navigated or frame changed between attempts causing JS execution errors; browser extension or CSP blocking injected script; clicking too fast after navigation so the execution context is destroyed.","solutions":["Fix the locator string syntax so the injected lookup JS does not throw (validate against supported locator formats)","Ensure the page has fully loaded and the correct frame/window is active before locating","Increase implicit waits / use waitFor before interacting, and re-locate after navigations","Inspect the wrapped cause (e2) in logs for the real script error (e.g. 'document is not defined', CSP violations)"],"exampleFix":"// before\ndriver.click(\"//input[@nme='username']\"); // typo causes JS lookup failure twice\n// after\ndriver.waitFor(\"//input[@name='username']\").click();","handlingStrategy":"retry","validationCode":"// sanity-check locator before use\nObjects.requireNonNull(locator);\nif (locator.isBlank()) throw new IllegalArgumentException(\"empty locator\");","typeGuard":null,"tryCatchPattern":"try {\n    driver.click(locator);\n} catch (Exception e) {\n    if (e.getMessage().contains(\"locator failed twice\")) {\n        driver.reload(); // recover page context, then retry once\n        driver.click(locator);\n    }\n}","preventionTips":["Wait for page readiness before locating after navigations","Validate locator syntax against supported formats","Log the wrapped cause to diagnose script-level failures"],"tags":["webdriver","locator","element-lookup","javascript-injection"],"backgroundTag":"entity-not-found","analyzedSha":"a22eb90246d958d15a47bf436693d0121ad2812d","analyzedAt":"2026-09-12T09:01:00.220Z","contentChangedAt":"2026-09-12T09:01:00.220Z","schemaVersion":2},"datasetVersion":"2026-09-19T12:17:13.211Z"}