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

  1. Provide at least one of `hasText`, `hasNotText`, `has`, or `hasNot`: `locator.filter({ hasText: 'Save' })`.
  2. When building filters conditionally, only call `.filter()` if at least one key is truthy.
  3. 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

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


AI-assisted analysis of vitest-dev/vitest@d568f8ce37 (2026-08-03). Data as JSON: /data/errors/05333d42011db35f.json. Report an issue: GitHub.