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.

Solutions

  1. Ensure the target element is attached to the DOM and is a descendant of options.root before calling
  2. Pass the correct root: finder(el, { root: el.closest('body') || document.documentElement }) or scope the root to a containing element
  3. If the element was captured earlier, re-query it at call time instead of holding a stale detached reference
  4. 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

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


AI-assisted analysis of didi/DoKit@626827cddb (2026-08-14). Data as JSON: /api/errors/daef76eca493c00f. Report an issue: GitHub.

Appendix: 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)