vitest-dev/vitest · error · Error

Expected DOM element to be an instance of Element, received

Error message

Expected DOM element to be an instance of Element, received ${typeof element}

What it means

Thrown by `convertElementToCssSelector` at tester-utils.ts:10-14 when its argument is falsy or not an `instanceof Element`. This helper builds a unique CSS selector for an element so it can be shipped to the browser-driver (Playwright/WebDriver) for interaction; passing anything other than a real DOM Element makes selector generation impossible.

Source

Thrown at packages/browser/src/client/tester/tester-utils.ts:11

import type { Locator, SelectorOptions, SerializedLocator, UserEventWheelDeltaOptions, UserEventWheelOptions } from 'vitest/browser'
import type { BrowserRPC } from '../client'
import type { BrowserTraceEntryStatus } from './trace'
import { __INTERNAL } from 'vitest/internal/browser'
import { getBrowserState, getWorkerState, now } from '../utils'
import { createBrowserTraceRangeId, recordBrowserTraceEntry } from './trace'

/* @__NO_SIDE_EFFECTS__ */
export function convertElementToCssSelector(element: Element): string {
  if (!element || !(element instanceof Element)) {
    throw new Error(
      `Expected DOM element to be an instance of Element, received ${typeof element}`,
    )
  }

  return getUniqueCssSelector(element)
}

function escapeIdForCSSSelector(id: string) {
  return id
    .split('')
    .map((char) => {
      const code = char.charCodeAt(0)

      if (char === ' ' || char === '#' || char === '.' || char === ':' || char === '[' || char === ']' || char === '>' || char === '+' || char === '~' || char === '\\') {
        // Escape common special characters with backslashes
        return `\\${char}`
      }
      else if (code >= 0x10000) {

View on GitHub (pinned to d568f8ce37)

Solutions

  1. Ensure the element exists in the DOM before resolving it; use `await page.locator(...).element()` or wait helpers.
  2. Unwrap refs/holders: pass `ref.current`, not the ref object.
  3. Add a null guard and fail with a clearer message if the element genuinely isn't present.

Example fix

// before
const el = document.querySelector('.maybe-gone')
convertElementToCssSelector(el) // el is null

// after
const el = document.querySelector('.maybe-gone')
if (!el) throw new Error('element missing')
convertElementToCssSelector(el)
Defensive patterns

Strategy: type-guard

Validate before calling

function isElement(v: unknown): v is Element {
  return v instanceof Element
}
if (!isElement(target)) throw new Error('target is not a DOM Element')

Type guard

function isElement(v: unknown): v is Element {
  return v instanceof Element
}

Prevention

When it happens

Trigger: Passing `null`/`undefined`, a text node, a Locator whose `.element()` returned null, a Window, or a serialized element stub. Triggered indirectly by locators and user-event utilities that ultimately call `convertElementToCssSelector`.

Common situations: A Locator resolved to nothing because the element wasn't in the DOM yet (timing). Selecting via `querySelector` that returned null and not guarding. Passing a React/Vue ref wrapper object instead of `.current`.

Related errors


AI-assisted analysis of vitest-dev/vitest@d568f8ce37 (2026-08-03). Data as JSON: /data/errors/087526821f58d90e.json. Report an issue: GitHub.