vitest-dev/vitest · error · UserInputElementTypeError
received value must an HTMLElement or an SVGElement or a Loc
Error message
received value must an HTMLElement or an SVGElement or a Locator that returns an HTMLElement or an SVGElement.
What it means
Thrown by `getElementFromUserInput` (as `UserInputElementTypeError`, a `GenericTypeError` subclass) when the value passed to an element-based matcher is neither an `HTMLElement`, an `SVGElement`, nor a `Locator` that resolves to one. The helper first unwraps a `Locator` via `.element()`, then checks `instanceof defaultView.HTMLElement || instanceof defaultView.SVGElement`; anything else (Document, Window, string, number, null, plain object, a Node that is not an Element) is rejected. The resulting message is the matcher-specific 'received value must … or a Locator that returns …' string.
Source
Thrown at packages/browser/src/client/tester/expect/utils.ts:55
elementOrLocator: Element | Locator | null,
// TODO: minifier doesn't keep names, so we need to update this
matcherFn: (...args: any) => any,
context: MatcherState,
): HTMLElement | SVGElement {
if (elementOrLocator instanceof Locator) {
elementOrLocator = elementOrLocator.element()
}
const defaultView = elementOrLocator?.ownerDocument?.defaultView || window
if (
elementOrLocator instanceof defaultView.HTMLElement
|| elementOrLocator instanceof defaultView.SVGElement
) {
return elementOrLocator
}
throw new UserInputElementTypeError(
elementOrLocator,
matcherFn,
context,
)
}
export function getNodeFromUserInput(
elementOrLocator: Element | Locator,
matcherFn: (...args: any) => any,
context: MatcherState,
): Node {
if (elementOrLocator instanceof Locator) {
elementOrLocator = elementOrLocator.element()
}
const defaultView = elementOrLocator.ownerDocument?.defaultView || window
if (View on GitHub (pinned to 1fa9837ec2)
Solutions
- Use a Locator: `expect(page.getByRole('button')).toBeVisible()` instead of passing a selector string.
- If you have a raw DOM node, ensure it is an Element (e.g. `document.querySelector('#x')`) and not a Document/NodeList.
- For elements from iframes, pass the iframe's content element directly or build a Locator scoped to the iframe.
Example fix
// before
expect('#submit').toBeVisible()
// after
expect(page.getByRole('button', { name: 'Submit' })).toBeVisible() Defensive patterns
Strategy: type-guard
Validate before calling
function isElementOrLocator(v: unknown): v is Element | Locator {
return v instanceof Element || (!!v && typeof v === 'object' && Symbol.for('$$vitest:locator') in v)
}
if (!isElementOrLocator(target)) throw new TypeError('pass an Element or Locator')
expect(target).toBeVisible() Type guard
function isElementOrLocator(v: unknown): v is Element | Locator {
return v instanceof Element
|| (!!v && typeof v === 'object' && Symbol.for('$$vitest:locator') in (v as object))
} Prevention
- Pass Element or Locator values, never selector strings.
- Use `page.getByRole(...)` / `page.locator(...)` to build Locators.
- Resolve `querySelector` results and null-check before passing.
When it happens
Trigger: Passing a CSS selector string instead of an element/Locator; passing `document` or `window`; passing the result of `querySelectorAll` (a NodeList); passing null/undefined; passing an element from a different document whose `defaultView` differs.
Common situations: Confusing `@testing-library`-style string selectors with Vitest browser matchers (which need a Locator); passing a detached or cross-frame element; refactor that swapped an element for its wrapper object.
Related errors
- received value must a Node or a Locator that returns a Node.
- Element not found: ${v.element}
- Invalid element or locator: ${elementOrLocator}. Expected an
- toHaveFormValues must be called with an object of expected f
- Multiple form elements with the same name must be of the sam
AI-assisted analysis of vitest-dev/vitest@1fa9837ec2 (2026-08-11).
Data as JSON: /api/errors/7651d01eebb0e9b8.
Report an issue: GitHub.