Errors and limits
What each failure code means, which are worth retrying, and why a refusal from a source is reported as a refusal rather than as an empty result.
Shape
{
"error": {
"code": "VALIDATION_FAILED",
"message": "Invalid request body",
"request_id": "req_…",
"retryable": false,
"details": { }
}
}retryable is the field to branch on. Nothing else in the error is a stable contract.
Codes
| Code | Meaning | Retry |
|---|---|---|
VALIDATION_FAILED | The request body does not match the schema | No — fix the request |
UNAUTHORIZED | Missing or unknown key | No |
QUOTA_EXCEEDED | A plan limit was reached | After the period resets |
NO_CAPACITY | No browser worker free | Yes, with backoff |
NO_IP_AVAILABLE | No healthy address for the country requested | Yes — often means a region is still warming up |
INVALID_URL | Blocked by the SSRF gates, or malformed | No |
BROWSER_FAILED | The page did not load | Yes, once |
RATE_LIMITED | Too many requests, from you or toward that domain | Yes, after the interval |
Refusals are not empty results
When a source answers 403 or 429, that is reported as an HTTP status on the response — not as a successful extraction with nothing in it. The distinction matters more than it looks: an empty result reads as "there is nothing there", which sends you to check your selectors, when the actual message was "slow down".
We record refusals with their date, stop, and do not put that source back on a schedule.
Politeness is enforced, not advisory
Requests toward one domain are paced regardless of how fast you send them. robots.txt is fetched and honoured, including crawl-delay. A disallowed path returns INVALID_URL rather than being fetched anyway.
There is no setting that turns this off, and support cannot turn it off for you. A source that refuses us once is a source nobody gets back, and the loss falls on every customer who needed it.
Last updated