{"record":{"id":"daef76eca493c00f","repo":"didi/DoKit","slug":"selector-was-not-found","errorCode":null,"errorMessage":"Selector was not found.","messagePattern":"Selector was not found\\.","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"Web/packages/core/src/common/js/finder/index.js","lineNumber":42,"sourceCode":"    seedMinLength: 1,\n    optimizedMinLength: 2,\n    threshold: 1000,\n  };\n  config = Object.assign({}, defaults, options);\n  rootDocument = findRootDocument(config.root, defaults);\n  let path = bottomUpSearch(input, Limit.All, () => bottomUpSearch(input, Limit.Two, () => bottomUpSearch(input, Limit.One)));\n  // console.log('bottomUpSearch:', path)\n  if (path) {\n    const optimized = sort(optimize(path, input));\n    // console.log('optimized:', optimized)\n    if (optimized.length > 0) {\n      path = optimized[0];\n    }\n    // console.log('last path:', path)\n    return selector(path);\n  }\n\n  throw new Error('Selector was not found.');\n}\nfunction findRootDocument(rootNode, defaults) {\n  if (rootNode.nodeType === Node.DOCUMENT_NODE) {\n    return rootNode;\n  }\n  if (rootNode === defaults.root) {\n    return rootNode.ownerDocument;\n  }\n  return rootNode;\n}\nfunction bottomUpSearch(input, limit, fallback) {\n  let path = null;\n  const stack = [];\n  let current = input;\n  let i = 0;\n  while (current && current !== config.root.parentElement) {\n    let level = maybe(id(current)) || maybe(...attr(current)) || maybe(...classNames(current)) || maybe(tagName(current)) || [any()];\n    const nth = index(current, level);","sourceCodeStart":24,"sourceCodeEnd":60,"githubUrl":"https://github.com/didi/DoKit/blob/626827cddb2feb2f3aee87a52a064b4e5ca2bed4/Web/packages/core/src/common/js/finder/index.js#L24-L60","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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)"],"exampleFix":"// before\nconst sel = finder(el, { root: document.body });\n\n// after\nif (!el.isConnected || !document.body.contains(el)) {\n  throw new Error('element detached; cannot build selector');\n}\nconst sel = finder(el, { root: document.body });","handlingStrategy":"validation","validationCode":"if (el.isConnected && document.body.contains(el)) {\n  const sel = finder(el, { root: document.body });\n}","typeGuard":null,"tryCatchPattern":"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; }","preventionTips":["Verify the element is a descendant of options.root before calling","Generate selectors synchronously right after capture; never store detached element references across renders"],"tags":["dom","css-selector","javascript","detached-node"],"backgroundTag":null,"analyzedSha":"626827cddb2feb2f3aee87a52a064b4e5ca2bed4","analyzedAt":"2026-08-14T12:45:58.758Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}