koala73/worldmonitor · error
PlaywrightProvider does not support search mode. Use Exa ins
Error message
PlaywrightProvider does not support search mode. Use Exa instead.
What it means
PlaywrightProvider implements the AcquisitionProvider interface but only for browser fetching: search() is a hard, unconditional throw because a local headless browser cannot perform web search. Any code path that resolves provider 'playwright' for a search operation hits this immediately. It is a deterministic contract violation, not a runtime condition — the message itself says to use Exa.
Source
Thrown at consumer-prices-core/src/acquisition/playwright.ts:58
}
const response = await page.goto(url, { waitUntil: 'domcontentloaded', timeout });
if (opts.waitForSelector) {
await page.waitForSelector(opts.waitForSelector, { timeout: 10_000 }).catch(() => {});
}
const html = await page.content();
const statusCode = response?.status() ?? 200;
return { url, html, statusCode, provider: this.name, fetchedAt: new Date() };
} finally {
await page.close();
}
}
async search(_query: string, _opts?: SearchOptions): Promise<SearchResult[]> {
throw new Error('PlaywrightProvider does not support search mode. Use Exa instead.');
}
async validate(): Promise<boolean> {
try {
await this.getContext();
return true;
} catch {
return false;
}
}
async teardown(): Promise<void> {
const timeout = new Promise<void>(r => setTimeout(r, 5000));
await Promise.race([
Promise.allSettled([this.context?.close(), this.browser?.close()]),
timeout,
]);
this.context = null;View on GitHub (pinned to a96956387a)
Solutions
- Route search to ExaProvider — search calls must resolve provider 'exa'
- Add a capability check before dispatching so only search-capable providers receive search work
- Fix the config: keep playwright in acquisition.provider/fallback (fetch) positions only
Example fix
// before — 'playwright' resolved for a search step
const provider = getProvider(config.provider); // === 'playwright'
await provider.search(query);
// after — dispatch search to a provider that supports it
const provider = getProvider('exa');
await provider.search(query); Defensive patterns
Strategy: validation
Validate before calling
const SEARCH_CAPABLE = new Set(['exa', 'firecrawl', 'p0']); // playwright.search() throws by design
// before dispatching search work
if (!SEARCH_CAPABLE.has(config.provider)) {
throw new Error(`provider '${config.provider}' cannot run search — use exa`);
} Type guard
function supportsSearch(p: AcquisitionProvider): boolean {
return p.name !== 'playwright'; // PlaywrightProvider.search is a hard throw
} Try / catch
try {
await provider.search(query);
} catch (err) {
if (err instanceof Error && err.message.includes('does not support search mode')) {
return await getProvider('exa').search(query); // reroute, do not retry
}
throw err;
} Prevention
- Model provider capabilities in config (fetch vs search) instead of assuming interface implies support
- Assert provider roles at startup: every search-mode step must resolve 'exa'
- Keep playwright out of discovery chains — it is fetch-only
When it happens
Trigger: An AcquisitionConfig with provider or fallback set to 'playwright' passed to a code path that calls search(); iterating the registry's provider map and calling search() on each entry; a config-driven chain that lists playwright under a search/discovery step.
Common situations: Copy-pasting a retailer acquisition config that worked for scrape into a discovery/search context; generic code that walks all providers assuming uniform capability; test suites exercising 'every provider implements search'.
Understand the failure class
Background: UnsupportedOperationException and "is not supported" errors: when a library deliberately refuses a call — this error's family across 30 libraries.
Related errors
- Exa search failed HTTP ${resp.status}: ${text.slice(0, 120)}
- Exa search failed for "${canonicalName}": ${detail}
- P0 search failed: HTTP ${resp.status}
AI-assisted analysis of koala73/worldmonitor@a96956387a (2026-08-21).
Data as JSON: /api/errors/f3c19661285281ff.
Report an issue: GitHub.