didi/DoKit · error · Error
Can't generate CSS selector for non-element node type.
Error message
Can't generate CSS selector for non-element node type.
What it means
Thrown by the CSS selector generator (a fork of the 'finder' library) when the node passed in is not an ELEMENT_NODE. The library builds a unique CSS selector by walking up the DOM from an element, so it can only operate on element nodes. Passing a text node, comment node, document, or document fragment triggers this immediately at the entry check.
Source
Thrown at Web/packages/core/src/common/js/finder/index.js:13
import cssesc from 'cssesc';
let Limit;
(function (Limit) {
Limit[Limit.All = 0] = 'All';
Limit[Limit.Two = 1] = 'Two';
Limit[Limit.One = 2] = 'One';
}(Limit || (Limit = {})));
let config;
let rootDocument;
export default function (input, options) {
if (input.nodeType !== Node.ELEMENT_NODE) {
throw new Error('Can\'t generate CSS selector for non-element node type.');
}
if (input.tagName.toLowerCase() === 'html') {
return 'html';
}
const defaults = {
root: document.body,
idName: name => true,
className: (name, input) => true,
tagName: name => true,
attr: (name, value) => false,
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)View on GitHub (pinned to 626827cddb)
Solutions
- Check node.nodeType === Node.ELEMENT_NODE (or node.nodeType === 1) before calling the finder
- Use element.children / parentElement instead of childNodes / parentNode when you need element-only traversal
- If the node is a text/comment node, pass its parentElement instead: node.parentElement
- Guard with instanceof: node instanceof Element (or the appropriate DOM class) before generating the selector
Example fix
// before
const selector = finder(node, { root: document.body });
// after
if (node && node.nodeType === Node.ELEMENT_NODE) {
const selector = finder(node, { root: document.body });
} else if (node && node.parentElement) {
const selector = finder(node.parentElement, { root: document.body });
} Defensive patterns
Strategy: type-guard
Validate before calling
const isElement = (n) => n && n.nodeType === Node.ELEMENT_NODE;
if (!isElement(node)) node = node && node.parentElement;
if (isElement(node)) selector = finder(node, { root: document.body }); Type guard
function isElementNode(node) {
return node instanceof Element;
} Prevention
- Prefer element.children and parentElement over childNodes and parentNode for element-only traversal
- Always narrow event.target / captured nodes with nodeType === 1 before selector generation
When it happens
Trigger: Calling the default export of finder/index.js with: a text node (nodeType 3) obtained via firstChild/childNodes[i], a comment node (nodeType 8), document (nodeType 9), documentFragment (nodeType 11), or the result of a DOM API that returns null/undefined coerced through a non-element accessor. Also happens when event.target is a text node (e.g. from a non-element context) and is fed directly to the finder.
Common situations: Recording user clicks for session replay or element-picker features: e.target is usually an element but can be a text node in some browsers/edge cases. Accessing parentNode of an element can return a document node. Using childNodes (returns all node types) instead of children (elements only).
Related errors
AI-assisted analysis of didi/DoKit@626827cddb (2026-08-14).
Data as JSON: /api/errors/0a10922583faa24d.
Report an issue: GitHub.