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

  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.