vitest-dev/vitest · error · Error
Element not found
Error message
Element not found: ${v.element} What it means
selectOptions accepts either string values or `{ element: SerializedLocator }` objects for `<option>` elements. For the object form the command resolves each locator to a Playwright ElementHandle; if the locator cannot be attached to a real DOM node (elementHandle() returns null), Vitest throws with the serialized locator text. This guards against silently selecting a detached/stale option.
Solutions
- Ensure the `<option>` exists in the DOM at call time: `await expect(select).toBeVisible()` and wait for options first.
- Prefer passing option values as plain strings (`selectOptions(select, ['apple'])`) when possible; the string path does not require resolving an ElementHandle.
- If using locators, build them right before the call rather than capturing and reusing across async gaps.
- Scope the option locator to the same frame/container as the select element.
Example fix
// before
const opt = page.getByRole('option', { name: 'Apple' })
// ... async work that removes the option ...
await userEvent.selectOptions(select, [{ element: opt }])
// after
await userEvent.selectOptions(select, [{ element: page.getByRole('option', { name: 'Apple' }) }])
// or, simplest:
await userEvent.selectOptions(select, ['apple']) Defensive patterns
Strategy: validation
Validate before calling
// ensure the option exists before passing it as { element }
const option = page.getByRole('option', { name: 'Apple' })
await expect(option).toBeVisible()
await userEvent.selectOptions(select, [{ element: option }]) Type guard
import type { SerializedLocator } from '@vitest/browser'
function isOptionObject(v: unknown): v is { element: SerializedLocator } {
return typeof v === 'object' && v !== null && 'element' in v
} Try / catch
try {
await userEvent.selectOptions(select, [{ element: optionLocator }])
} catch (err) {
if (err instanceof Error && err.message.startsWith('Element not found')) {
// re-query the option or fall back to a value string
await userEvent.selectOptions(select, ['apple'])
} else {
throw err
}
} Prevention
- Prefer option value strings over element locators for selectOptions.
- Wait for options to render before selecting (toBeVisible / findByRole).
- Build option locators immediately before use; do not reuse across async gaps.
When it happens
Trigger: Calling `userEvent.selectOptions(select, [{ element: page.getByRole('option', { name: 'X' }) }])` when the option is not present, has been removed since the locator was created, is inside a shadow root the locator cannot reach, or the select has not yet rendered the options (timing).
Common situations: Selecting from a lazy-loaded option list before options render; option removed by virtualization after the locator was captured; selecting inside an iframe without scoping the locator; passing a locator built against the wrong frame.
Related errors
- Expected element or locator to be an instance of Element or…
- Invalid element or locator
- received value must an HTMLElement or an SVGElement or a…
- aria adapter expects an Element
- Cannot upload files outside of a test
AI-assisted analysis of vitest-dev/vitest@1fa9837ec2 (2026-08-11).
Data as JSON: /api/errors/8ab4a1c6ad192380.
Report an issue: GitHub.
Appendix: source
Thrown at packages/browser-playwright/src/commands/select.ts:22
import type { UserEventCommand } from './utils'
import { getDescribedLocator } from './utils'
export const selectOptions: UserEventCommand<UserEvent['selectOptions']> = async (
context,
selector,
userValues,
options = {},
) => {
const value = userValues as any as (string | { element: SerializedLocator })[]
const selectElement = getDescribedLocator(context, selector)
const values = await Promise.all(value.map(async (v) => {
if (typeof v === 'string') {
return v
}
const elementHandler = await getDescribedLocator(context, v.element).elementHandle()
if (!elementHandler) {
throw new Error(`Element not found: ${v.element}`)
}
return elementHandler
})) as (readonly string[]) | (readonly ElementHandle[])
await selectElement.selectOption(values, options)
}
View on GitHub (pinned to 1fa9837ec2)