koala73/worldmonitor · error
P0 error: ${data.error ?? 'no content'}
Error message
P0 error: ${data.error ?? 'no content'} What it means
Thrown by P0Provider.fetch() when POST /scrape answers HTTP 2xx but the JSON body has success:false AND no html payload. This is P0 reporting a scrape-level failure in-band: the render timed out, the proxy was blocked by the target, or the page never produced content — data.error carries P0's own message ('no content' when absent). Unlike the HTTP-status error, the transport was fine; the page acquisition itself failed.
Source
Thrown at consumer-prices-core/src/acquisition/p0.ts:58
const resp = await fetch(`${this.baseUrl}/scrape`, {
method: 'POST',
headers: this.headers(),
body: JSON.stringify({
url,
render_js: true,
wait_for: opts.waitForSelector,
timeout: Math.floor((opts.timeout ?? 30_000) / 1_000),
output_format: 'html',
premium_proxy: true,
}),
signal: AbortSignal.timeout((opts.timeout ?? 30_000) + 10_000),
});
if (!resp.ok) throw new Error(`P0 scrape failed: HTTP ${resp.status}`);
const data = (await resp.json()) as P0ScrapeResponse;
if (!data.success && !data.html) {
throw new Error(`P0 error: ${data.error ?? 'no content'}`);
}
return {
url,
html: data.html ?? '',
markdown: data.markdown,
statusCode: data.statusCode ?? 200,
provider: this.name,
fetchedAt: new Date(),
};
}
async search(query: string, opts: SearchOptions = {}): Promise<SearchResult[]> {
const resp = await fetch(`${this.baseUrl}/search`, {
method: 'POST',
headers: this.headers(),
body: JSON.stringify({
query,View on GitHub (pinned to eeab0a219f)
Solutions
- Read the interpolated data.error — it distinguishes render timeout from blocked-by-target from no content
- Raise opts.timeout (it becomes seconds) or drop waitForSelector when the selector is unreliable on that retailer
- If one whole domain is blocked, move that retailer to another provider via acquisition.fallback
- Verify wait selectors against the live page before encoding them in config
Example fix
// before — default 30s budget with a selector that rarely resolves
await p0.fetch(url, { waitForSelector: '#price' });
// after — larger render budget; selector stays best-effort
await p0.fetch(url, { waitForSelector: '#price', timeout: 60_000 }); Defensive patterns
Strategy: fallback
Validate before calling
// sanity-check the render budget before sending: P0 takes floor(ms/1000) seconds
const secs = Math.floor((opts.timeout ?? 30_000) / 1000);
if (secs < 5) throw new RangeError('P0 render budget too small — raise opts.timeout'); Type guard
function isP0ContentError(err: unknown): boolean {
return err instanceof Error && err.message.startsWith('P0 error:');
} Try / catch
try {
return await p0.fetch(url, opts);
} catch (err) {
if (isP0ContentError(err)) {
// in-band scrape failure: retry once selector-free, then fall back
return await p0.fetch(url, { ...opts, waitForSelector: undefined });
}
throw err;
} Prevention
- Treat selector waits as best-effort: retry once without waitForSelector before abandoning
- Track P0 success rate per domain — a sudden block shows up as success:false clusters on one retailer
- Remember the ms-to-seconds conversion: P0 takes floor(timeout/1000), so tiny budgets fail instantly
When it happens
Trigger: A JS-heavy page exceeding the render budget sent as floor(timeout/1000) seconds; anti-bot defenses defeating premium_proxy for a specific domain; a waitForSelector (opts.waitForSelector) that never appears on the page; P0 returning success:false with an empty error string.
Common situations: A retailer's CDN starts blocking P0 egress IPs so every product page on that domain returns success:false; a selector typo makes every scrape wait until timeout; a small opts.timeout truncating to near-zero seconds after the ms-to-s conversion so renders fail immediately.
Related errors
- P0 scrape failed: HTTP ${resp.status}
- Firecrawl extract error: ${data.error ?? 'unknown'}
- P0 search failed: HTTP ${resp.status}
AI-assisted analysis of koala73/worldmonitor@eeab0a219f (2026-08-21).
Data as JSON: /api/errors/f391e53c52f6847b.
Report an issue: GitHub.