grafana/k6 · error
node is not queryable
Error message
node is not queryable
What it means
Mapped from 'error:notqueryablenode' by errorFromDOMError (element_handle.go:1896-1916). The injected DOM engine can only run element queries on nodes that are queryable; calling $/$$ (querySelector) on a handle whose underlying remote object is not such a node (a text node, a plain JS value, or a node in a detached context) yields this error.
Source
Thrown at internal/js/modules/k6/browser/common/element_handle.go:1915
"error:notelement": "node is not an element",
"error:nothtmlelement": "not an HTMLElement",
"error:notfillableelement": "element is not an <input>, <textarea> or [contenteditable] element",
"error:notfillableinputtype": "input of this type cannot be filled",
"error:notfillablenumberinput": "cannot type text into input[type=number]",
"error:notvaliddate": "malformed value",
"error:notinput": "node is not an HTMLInputElement",
"error:notfile": "node is not an input[type=file] element",
"error:hasnovalue": "node is not an HTMLInputElement or HTMLTextAreaElement or HTMLSelectElement",
"error:notselect": "element is not a <select> element",
"error:notcheckbox": "not a checkbox or radio button",
"error:notmultiplefileinput": "non-multiple file input can only accept single file",
"error:strictmodeviolation": "strict mode violation, multiple elements returned for selector query",
"error:notqueryablenode": "node is not queryable",
"error:nthnocapture": "can't query n-th element in a chained selector with capture",
"error:intercept": "another element is intercepting with pointer action",
}
if err, ok := errs[serr]; ok {
return errors.New(err)
}
return errors.New(serr)
}
View on GitHub (pinned to 01ffac6f24)
Solutions
- Convert/validate the handle first: use handle.asElement() (returns null for non-elements) before querying
- Re-query from the frame or page after navigation instead of reusing pre-navigation handles
- For non-element nodes, use page.evaluate with a native querySelector inside the page function
- Dispose stale handles and acquire fresh ones on the current frame
Example fix
// before
const h = await page.evaluateHandle(() => document.body.firstChild);
await h.$('div'); // text node: not queryable
// after
const h = await page.evaluateHandle(() => document.body);
await h.$('div'); Defensive patterns
Strategy: type-guard
Type guard
// asElement() returns null for non-element handles
const raw = await page.evaluateHandle(() => document.body.firstChild);
const el = raw.asElement(); // null unless it is an element
if (el) {
const child = await el.$('div');
} Try / catch
try {
await handle.$('div');
} catch (e) {
if (/not queryable/.test(e.message)) {
const el = handle.asElement();
if (!el) throw new Error('handle is not an element; re-query with page.$');
} else throw e;
} Prevention
- Always run asElement() after evaluateHandle before querying
- Use page.$/frame.$ for element lookups, evaluateHandle only for real JS values
- Discard handles captured before page.goto and re-query afterwards
When it happens
Trigger: Getting a handle to a non-element node and querying it: const h = await page.evaluateHandle(() => document.body.firstChild); await h.$('div'); calling elementHandle.$ on a JSHandle obtained from evaluateHandle that wraps null, a primitive, or a text node; querying a handle whose frame was detached by navigation.
Common situations: Using evaluateHandle for flexibility and then treating the result as an element; holding handles across page.goto where the old context is destroyed; grabbing childNodes instead of children.
Related errors
- Error while parsing selector `${selector}` - unexpected symb
- Error while parsing selector `${selector}`: ${e.message}
- Error while parsing selector `${selector}` - cannot use ${op
- "${attr.name}" does not support "${attr.op}" matcher
- "name" attribute must have a value
AI-assisted analysis of grafana/k6@01ffac6f24 (2026-08-18).
Data as JSON: /api/errors/07e50a4f986cf6d9.
Report an issue: GitHub.