vitest-dev/vitest · warning · TypeError
Expecting a valid DOM element, but got ${typeName}.
Error message
Expecting a valid DOM element, but got ${typeName}. What it means
Thrown by prettyDOM (packages/browser/src/client/tester/context.ts:547-568), which is invoked by page.debug(). After resolving a Locator to its element and defaulting null to document.body, the function checks that the value is an object with an outerHTML property; anything else (number, string, plain object without outerHTML, undefined leaked through) is rejected as a TypeError with the constructor name or typeof result.
Source
Thrown at packages/browser/src/client/tester/context.ts:567
maxLength: number = Number(defaultOptions?.maxLength ?? import.meta.env.DEBUG_PRINT_LIMIT ?? 7000),
prettyFormatOptions: PrettyDOMOptions = {},
): string {
if (maxLength === 0) {
return ''
}
if (!dom) {
dom = document.body
}
if ('element' in dom && 'all' in dom) {
dom = dom.element()
}
const type = typeof dom
if (type !== 'object' || !dom.outerHTML) {
const typeName = type === 'object' ? dom.constructor.name : type
throw new TypeError(`Expecting a valid DOM element, but got ${typeName}.`)
}
const pretty = stringify(dom, Number.POSITIVE_INFINITY, {
maxLength,
highlight: true,
...defaultOptions,
...prettyFormatOptions,
})
return dom.outerHTML.length > maxLength
? `${pretty.slice(0, maxLength)}...`
: pretty
}
function getElementError(selector: string | Locator, container: Element): Error {
const locator = typeof selector === 'string' ? __INTERNAL._asLocator('javascript', selector) : selector.asLocator()
const formatted = formatDOM(container)
const error = new Error(`Cannot find element with locator: ${locator}\n\n${formatted}`)
error.name = 'VitestBrowserElementError'View on GitHub (pinned to d568f8ce37)
Solutions
- Pass a single Element or Locator: page.debug(document.querySelector('.x')).
- For a NodeList/array, iterate: nodes.forEach(n => page.debug(n)) or use page.debug(Array.from(nodes)) (debug accepts arrays at context.ts:537-540).
- Coerce before debugging: page.debug(typeof v === 'string' ? document.body : v).
Example fix
// before
page.debug(document.querySelectorAll('.item'))
// after
page.debug(Array.from(document.querySelectorAll('.item'))) Defensive patterns
Strategy: type-guard
Validate before calling
function isDebuggable(v: unknown): v is Element | Locator | (Element | Locator)[] {
if (Array.isArray(v)) return v.every(isDebuggable)
return v instanceof Element || (v != null && typeof v === 'object' && 'element' in v && 'all' in v)
}
if (isDebuggable(maybeNode)) page.debug(maybeNode as any) Type guard
function isDebuggableNode(v: unknown): v is Element | Locator {
return v instanceof Element || (v != null && typeof v === 'object' && 'element' in (v as any) && 'all' in (v as any))
} Prevention
- Pass only Element, Locator, or arrays thereof to page.debug.
- Convert NodeList via Array.from(...) before debugging.
When it happens
Trigger: Calling page.debug(value) where value is a primitive (string/number), a plain JS object, a NodeList (which has no outerHTML), or an array element passed singularly that isn't a DOM Element/Locator. Also triggered if a Locator.element() returned something unexpected.
Common situations: Passing the result of querySelectorAll (a NodeList) instead of a single node; passing an event target that isn't an Element; debugging with console.log-style arguments into page.debug.
Related errors
- aria adapter expects an Element
- Element not found: ${v.element}
- Invalid element or locator: ${elementOrLocator}. Expected an
- .toContainHTML() expects a string value, got ${htmlText}
- .toHaveDisplayValue() currently supports only input, textare
AI-assisted analysis of vitest-dev/vitest@d568f8ce37 (2026-08-03).
Data as JSON: /data/errors/66b411079c0009c1.json.
Report an issue: GitHub.