vitest-dev/vitest · error · Error

Expected element or locator to be defined.

Error message

Expected element or locator to be defined.

What it means

Thrown by `serializeElement` when `elementOrLocator` is falsy (null/undefined). The function needs a concrete element or Locator to produce a `SerializedLocator` (selector + human-readable locator string) that can be sent over RPC to the browser command server. A null/undefined input has no selector representation, so it is rejected before any serialization step.

Solutions

  1. Null-check before serializing: `if (el) await serializeElement(el)`.
  2. Resolve Locators in strict mode so a missing element fails earlier with a descriptive error.
  3. Ensure the upstream query/Locator actually returns an element before forwarding.

Example fix

// before
await serializeElement(maybeEl)

// after
if (!maybeEl) throw new Error('element not found')
await serializeElement(maybeEl)
Defensive patterns

Strategy: validation

Validate before calling

if (!elementOrLocator) {
  throw new Error('Cannot serialize: element or locator is null/undefined')
}
await serializeElement(elementOrLocator)

Prevention

When it happens

Trigger: Passing `null`/`undefined` to `serializeElement`; a Locator that resolved to nothing and was then forwarded; an optional-chain expression that yielded undefined.

Common situations: A `querySelector` that returned null being forwarded without a null check; a Locator `.element()` returning null in non-strict mode; refactor that dropped a guard.

Related errors


AI-assisted analysis of vitest-dev/vitest@1fa9837ec2 (2026-08-11). Data as JSON: /api/errors/8ed4b34813adcb2f. Report an issue: GitHub.

Appendix: source

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

    return String(re)
  }
  // Even number of backslashes followed by the quote -> insert a backslash.
  return String(re).replace(/(^|[^\\])(\\\\)*(["'`])/g, '$1$2\\$3').replace(/>>/g, '\\>\\>')
}

export function escapeForTextSelector(text: string | RegExp, exact: boolean): string {
  if (typeof text !== 'string') {
    return escapeRegexForSelector(text)
  }
  return `${JSON.stringify(text)}${exact ? 's' : 'i'}`
}

const provider = getBrowserState().provider
const kElementLocator = Symbol.for('$$vitest:locator-resolved')

export async function serializeElement(elementOrLocator: Element | Locator, options?: SelectorOptions): Promise<SerializedLocator> {
  if (!elementOrLocator) {
    throw new Error('Expected element or locator to be defined.')
  }
  if (elementOrLocator instanceof Element) {
    const selector = convertElementToCssSelector(elementOrLocator)
    return { selector, locator: __INTERNAL._asLocator('javascript', selector) }
  }
  if (isLocator(elementOrLocator)) {
    if (provider === 'playwright' || kElementLocator in elementOrLocator) {
      return elementOrLocator.serialize()
    }
    const element = await elementOrLocator.findElement(options)
    const selector = convertElementToCssSelector(element)
    const locator = __INTERNAL._asLocator('javascript', selector)
    return { selector, locator }
  }
  throw new Error('Expected element or locator to be an instance of Element or Locator.')
}

const kLocator = Symbol.for('$$vitest:locator')

View on GitHub (pinned to 1fa9837ec2)