didi/DoKit · error · Error
Selector was not found.
Error message
Selector was not found.
What it means
Thrown when the bottom-up selector search completely fails to produce any candidate path for the input element. bottomUpSearch walks from the element up to config.root; if it never builds a stack that resolves to a unique selector (all three fallback limits All/Two/One return null), the function throws. Usually this means the element is detached from the root, or every candidate selector fails the uniqueness query.
Source
Thrown at Web/packages/core/src/common/js/finder/index.js:42
seedMinLength: 1,
optimizedMinLength: 2,
threshold: 1000,
};
config = Object.assign({}, defaults, options);
rootDocument = findRootDocument(config.root, defaults);
let path = bottomUpSearch(input, Limit.All, () => bottomUpSearch(input, Limit.Two, () => bottomUpSearch(input, Limit.One)));
// console.log('bottomUpSearch:', path)
if (path) {
const optimized = sort(optimize(path, input));
// console.log('optimized:', optimized)
if (optimized.length > 0) {
path = optimized[0];
}
// console.log('last path:', path)
return selector(path);
}
throw new Error('Selector was not found.');
}
function findRootDocument(rootNode, defaults) {
if (rootNode.nodeType === Node.DOCUMENT_NODE) {
return rootNode;
}
if (rootNode === defaults.root) {
return rootNode.ownerDocument;
}
return rootNode;
}
function bottomUpSearch(input, limit, fallback) {
let path = null;
const stack = [];
let current = input;
let i = 0;
while (current && current !== config.root.parentElement) {
let level = maybe(id(current)) || maybe(...attr(current)) || maybe(...classNames(current)) || maybe(tagName(current)) || [any()];
const nth = index(current, level);View on GitHub (pinned to 626827cddb)
Solutions
- Ensure the target element is attached to the DOM and is a descendant of options.root before calling
- Pass the correct root: finder(el, { root: el.closest('body') || document.documentElement }) or scope the root to a containing element
- If the element was captured earlier, re-query it at call time instead of holding a stale detached reference
- Wrap the call in try-catch and fall back to a manual path built from element metadata (id, data attributes)
Example fix
// before
const sel = finder(el, { root: document.body });
// after
if (!el.isConnected || !document.body.contains(el)) {
throw new Error('element detached; cannot build selector');
}
const sel = finder(el, { root: document.body }); Defensive patterns
Strategy: validation
Validate before calling
if (el.isConnected && document.body.contains(el)) {
const sel = finder(el, { root: document.body });
} Try / catch
try { sel = finder(el, opts); } catch (e) { if (e.message === 'Selector was not found.') { /* re-query element and retry once, or fall back to manual locator */ } else throw e; } Prevention
- Verify the element is a descendant of options.root before calling
- Generate selectors synchronously right after capture; never store detached element references across renders
When it happens
Trigger: Calling the finder on an element that is not a descendant of options.root (default document.body), on an element removed from the DOM between capture and call, or on an element inside a shadow root / iframe document that is not reachable from the root document. Also occurs when config.root.parentElement logic terminates the walk before a unique path is found and findUniquePath returns null at every limit.
Common situations: Generating selectors for elements inside <template> contents, detached jQuery/React elements, shadow DOM, or elements moved after being captured. Using a custom options.root that does not contain the target element.
Related errors
- Can't generate CSS selector for non-element node type.
- Can't select any node with this selector: ${selector(path)}
AI-assisted analysis of didi/DoKit@626827cddb (2026-08-14).
Data as JSON: /api/errors/daef76eca493c00f.
Report an issue: GitHub.