vitest-dev/vitest · error · Error
Locator.filter expects at least one filter. None provided.
Error message
Locator.filter expects at least one filter. None provided.
What it means
Thrown by `Locator.filter` at locators.ts:297-298 when none of the supported filter keys (`hasText`, `hasNotText`, `has`, `hasNot`) are present on the options object. Calling `.filter()` with no constraints is meaningless and would just rebuild the same locator, so Vitest requires at least one.
Source
Thrown at packages/browser/src/client/tester/locators.ts:298
selectors.push(`internal:has-text=${escapeForTextSelector(filter.hasText, false)}`)
}
if (filter?.hasNotText) {
selectors.push(`internal:has-not-text=${escapeForTextSelector(filter.hasNotText, false)}`)
}
if (filter?.has) {
const locator = filter.has as Locator
selectors.push(`internal:has=${JSON.stringify(locator._pwSelector || locator.selector)}`)
}
if (filter?.hasNot) {
const locator = filter.hasNot as Locator
selectors.push(`internal:has-not=${JSON.stringify(locator._pwSelector || locator.selector)}`)
}
if (!selectors.length) {
throw new Error(`Locator.filter expects at least one filter. None provided.`)
}
return this.locator(selectors.join(' >> '))
}
public and(locator: Locator): Locator {
return this.locator(`internal:and=${JSON.stringify(locator._pwSelector || locator.selector)}`)
}
public or(locator: Locator): Locator {
return this.locator(`internal:or=${JSON.stringify(locator._pwSelector || locator.selector)}`)
}
public query(): HTMLElement | SVGElement | null {
const parsedSelector = this._parsedSelector || (this._parsedSelector = selectorEngine.parseSelector(this._pwSelector || this.selector))
return selectorEngine.querySelector(parsedSelector, document.documentElement, true) as HTMLElement | SVGElement
}
View on GitHub (pinned to d568f8ce37)
Solutions
- Provide at least one of `hasText`, `hasNotText`, `has`, or `hasNot`: `locator.filter({ hasText: 'Save' })`.
- When building filters conditionally, only call `.filter()` if at least one key is truthy.
- Double-check key names against the `LocatorOptions` type (e.g. it's `hasText`, not `text`).
Example fix
// before
const opts = condition ? { hasText: 'x' } : {}
locator.filter(opts)
// after
const opts = condition ? { hasText: 'x' } : null
if (opts) locator.filter(opts) Defensive patterns
Strategy: validation
Validate before calling
type FilterOptions = { hasText?: unknown; hasNotText?: unknown; has?: unknown; hasNot?: unknown }
function hasAnyFilter(o: Partial<FilterOptions>): boolean {
return !!(o.hasText ?? o.hasNotText ?? o.has ?? o.hasNot)
}
if (!hasAnyFilter(opts)) throw new Error('provide at least one filter') Type guard
function hasFilterKey(o: unknown): o is { hasText?: unknown; hasNotText?: unknown; has?: unknown; hasNot?: unknown } {
return !!o && typeof o === 'object' && ('hasText' in o || 'hasNotText' in o || 'has' in o || 'hasNot' in o)
} Prevention
- Always supply at least one of hasText/hasNotText/has/hasNot to .filter().
- Build filter objects conditionally and skip .filter() when empty.
- Remember the correct key names; level/text-only keys are ignored.
When it happens
Trigger: `page.locator('div').filter({})`, `.filter()` with an object containing only unknown keys, or `.filter({ level: 2 })`. Also when destructuring options that turn out undefined: `.filter({ hasText: maybeUndefined })`.
Common situations: Building filter options dynamically and ending up with all-undefined values. Copy-paste from another locator that dropped the relevant key. Misremembering the supported filter keys.
Related errors
- toHaveFormValues must be called with an object of expected f
- expected selection must be a string or undefined
- input with type=checkbox or type=radio cannot be used with .
- 'toMatchScreenshot' cannot be used with "not"
- received value must ${expectedString} or a Locator that retu
AI-assisted analysis of vitest-dev/vitest@d568f8ce37 (2026-08-03).
Data as JSON: /data/errors/05333d42011db35f.json.
Report an issue: GitHub.