vitest-dev/vitest · error · UserInputElementTypeError
received value must ${expectedString} or a Locator that retu
Error message
received value must ${expectedString} or a Locator that returns ${expectedString}. What it means
Thrown via the `UserInputElementTypeError` class (utils.ts:55, 192-200) which subclasses `GenericTypeError` with the expected string `'an HTMLElement or an SVGElement'`. It fires from `getElementFromUserInput` (utils.ts:42-60) when the resolved value is neither an `HTMLElement` nor an `SVGElement` of its owner document's defaultView. The message template lives at utils.ts:184-188.
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 d568f8ce37)
Solutions
- Ensure you pass a DOM Element (e.g. `document.querySelector('button')`) or a Vitest Locator that resolves to one.
- For iframe contents, resolve the element through that iframe's document so `instanceof` matches the correct realm.
- If you hold a Node, walk up to its parentElement/ownerDocument.documentElement to obtain an Element.
Example fix
// before
expect(document).toHaveValue('x')
// after
expect(document.querySelector('input')!).toHaveValue('x') Defensive patterns
Strategy: type-guard
Validate before calling
function isHtmlOrSvg(el: unknown, view: Window = window): boolean {
return el instanceof view.HTMLElement || el instanceof view.SVGElement
}
if (!isHtmlOrSvg(target)) throw new Error('expected HTMLElement or SVGElement') Type guard
function isHtmlOrSvgElement(el: unknown, view: Window = window): el is HTMLElement | SVGElement {
return el instanceof view.HTMLElement || el instanceof view.SVGElement
} Prevention
- Pass real DOM Elements or Vitest Locators to matchers; never document/window.
- When working with iframes, resolve elements from that iframe's document so realms match.
- Use querySelector/Locator methods that return Elements, not text nodes or wrappers.
When it happens
Trigger: Passing a text node, a Document, a Window, a plain object, a number, or a Locator whose `element()` resolves to a non-element Node to any matcher that calls `getElementFromUserInput` (e.g. `toBeChecked`, `toHaveValue`, `toHaveSelection`, `toHaveFormValues`). Cross-realm element instances whose constructor differs from the document's `defaultView.HTMLElement` also fail.
Common situations: Passing `document` or `window` by mistake. Grabbing a text node via `element.firstChild`. Element coming from an iframe whose `defaultView` differs. Serializer returning a wrapper object instead of a real Element.
Related errors
- toHaveFormValues must be called on a form or a fieldset, ins
- Expected DOM element to be an instance of Element, received
- Expected element or locator to be an instance of Element or
- Multiple form elements with the same name must be of the sam
- input with type=checkbox or type=radio cannot be used with .
AI-assisted analysis of vitest-dev/vitest@d568f8ce37 (2026-08-03).
Data as JSON: /data/errors/c503fc1daf79dd1c.json.
Report an issue: GitHub.