vitest-dev/vitest · error · TypeError
Expecting a valid DOM element, but got
Error message
Expecting a valid DOM element, but got ${typeName}. What it means
prettyDOM() (exposed as page.utils.prettyDOM / debug) stringifies an Element for diagnostic output. After resolving a falsy argument to document.body and unwrapping a Locator via .element(), it checks typeof === 'object' and the presence of outerHTML. If the value is a primitive, null, or a non-Element object, it throws a TypeError naming the offending constructor/type. This usually indicates a Locator that resolved to nothing or a non-DOM object.
Solutions
- Resolve Locators first: prettyDOM(await locator.element()).
- Verify the value is truthy before calling: if (!el) return;
- For arrays/NodeLists, iterate and stringify each Element individually.
- Check `value instanceof Element` before prettyDOM to fail with a clearer message.
Example fix
// before
console.log(page.utils.prettyDOM(page.getByRole('button')))
// after
const el = await page.getByRole('button').element()
if (el) console.log(page.utils.prettyDOM(el)) Defensive patterns
Strategy: type-guard
Validate before calling
if (!dom || typeof dom !== 'object' || !(dom instanceof Element)) {
throw new TypeError('prettyDOM needs an Element')
}
page.utils.prettyDOM(dom) Type guard
function isElement(v: unknown): v is Element {
return typeof Element !== 'undefined' && v instanceof Element
} Prevention
- Resolve Locators via await locator.element() before passing to prettyDOM/debug.
- Check the value is truthy and an Element before formatting.
- Iterate NodeLists/arrays individually instead of passing them directly.
When it happens
Trigger: Passing a Locator whose element() returns null/undefined to prettyDOM/debug; passing a number/string/boolean; passing an object that lacks outerHTML (e.g. a plain JS object, a NodeList, or a Window); calling debug() on a stale reference after the node was removed.
Common situations: Logging a Locator for debugging without awaiting/resolving it; refactors that changed a query to return a NodeList or array; SSR/jsdom mismatches where Element constructor differs.
Related errors
- aria adapter expects an Element
- Invalid element or locator
- Element not found
- Expected DOM element to be an instance of Element, received
- Expected element or locator to be an instance of Element or…
AI-assisted analysis of vitest-dev/vitest@1fa9837ec2 (2026-08-11).
Data as JSON: /api/errors/66b411079c0009c1.
Report an issue: GitHub.
Appendix: 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 1fa9837ec2)