{"record":{"id":"107c6ff3b29ff492","repo":"CloakHQ/CloakBrowser","slug":"element-selector-failed-target-identity-check-107c6f","errorCode":null,"errorMessage":"Element '{selector}' failed target_identity check: selector resolved to a different element before input dispatch","messagePattern":"Element '(.+?)' failed target_identity check: selector resolved to a different element before input dispatch","errorType":"exception","errorClass":"ElementTargetChangedError","httpStatus":null,"severity":"error","filePath":"dotnet/src/CloakBrowser/Human/Actionability.cs","lineNumber":355,"sourceCode":"        double y,\n        double timeoutMs = 5000,\n        IsolatedWorld? stealth = null)\n    {\n        if (stealth == null)\n            throw new StealthWorldUnavailableError();\n\n        double deadline = NowMs() + timeoutMs;\n        int attempt = 0;\n\n        while (true)\n        {\n            var (status, hit, covering, _) = await StealthDom.ValidateAsync(\n                stealth, selector, targetId, gen, x, y).ConfigureAwait(false);\n\n            if (status == StealthStatus.Unsupported)\n                throw new UnsupportedHumanizeSelectorError(selector);\n            if (status == StealthStatus.Stale)\n                throw new ElementTargetChangedError(selector);\n            if (status == StealthStatus.NotFound)\n                throw new ElementNotAttachedError(selector);\n            if (status == StealthStatus.EvaluationFailed)\n            {\n                if (NowMs() >= deadline)\n                    throw new StealthEvaluationError(selector);\n            }\n            else if (status == StealthStatus.Ok && hit)\n            {\n                return;\n            }\n            else if (status == StealthStatus.Ok)\n            {\n                if (NowMs() >= deadline)\n                    throw new ElementNotReceivingEventsError(selector, covering);\n            }\n            else\n            {","sourceCodeStart":337,"sourceCodeEnd":373,"githubUrl":"https://github.com/CloakHQ/CloakBrowser/blob/d6bad5de261bedf025280ace1d14e800aee13923/dotnet/src/CloakBrowser/Human/Actionability.cs#L337-L373","documentation":"ElementTargetChangedError is thrown inside the identity-aware CheckPointerEventsAsync loop when StealthDom.ValidateAsync returns StealthStatus.Stale: the selector now resolves to a different element (or generation) than the one identified by targetId/gen at resolution time. This guards against input being dispatched at coordinates computed for a node that the page has since swapped.","triggerScenarios":"Between resolving the element (capturing targetId and gen) and revalidating the click point, an SPA re-render replaces the DOM node so ValidateAsync flags the target as stale; list re-ordering, virtualization, or A/B swaps that mount a new node for the same selector.","commonSituations":"React/Vue keyed re-renders that recreate nodes, infinite-scroll lists shifting elements, click-then-pipeline flows that pause (delays, retries) long enough for the page to mutate, slow humanized typing letting the DOM churn underneath.","solutions":["Re-resolve the element (fresh snapshot for a new targetId/gen) immediately before dispatching input, in a tight retry loop.","Use a stable selector attribute (data-testid) so resolution is deterministic and reduce delay between resolution and dispatch.","If replacement is expected and the new node is equivalent, re-run the full humanized action against the fresh target."],"exampleFix":"// before\nvar snap = await StealthDom.SnapshotAsync(world, sel);\nawait Task.Delay(1500); // DOM swaps the node meanwhile\nawait Actionability.CheckPointerEventsAsync(page, sel, snap.Value.TargetId, snap.Value.Gen, x, y, stealth: world);\n\n// after\nvar snap = await StealthDom.SnapshotAsync(world, sel);\nawait Actionability.CheckPointerEventsAsync(page, sel, snap.Value.TargetId, snap.Value.Gen, x, y, stealth: world); // validate immediately","handlingStrategy":"retry","validationCode":"var (status, _, _, _) = await StealthDom.ValidateAsync(world, sel, targetId, gen, x, y);\nif (status == StealthStatus.Stale) { /* re-snapshot and use fresh TargetId/Gen before dispatch */ }","typeGuard":null,"tryCatchPattern":"catch (ElementTargetChangedError)\n{\n    var snap = await StealthDom.SnapshotAsync(world, sel);\n    if (snap.status == StealthStatus.Ok)\n        await Actionability.CheckPointerEventsAsync(page, sel, snap.Value.TargetId, snap.Value.Gen, x, y, timeoutMs, world);\n}","preventionTips":["Keep the resolution-to-dispatch window as short as possible in dynamic pages.","Re-validate target identity right before every input dispatch.","Retry the whole action when SPAs swap nodes; treat stale as 'redownload the target', not a hard failure."],"tags":["actionability","stale-element","dom-mutation"],"backgroundTag":"stale-element-reference","analyzedSha":"d6bad5de261bedf025280ace1d14e800aee13923","analyzedAt":"2026-08-28T14:13:12.918Z","schemaVersion":2},"datasetVersion":"2026-08-28T16:17:29.566Z"}