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

  1. Resolve Locators first: prettyDOM(await locator.element()).
  2. Verify the value is truthy before calling: if (!el) return;
  3. For arrays/NodeLists, iterate and stringify each Element individually.
  4. 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

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


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)