Errors and retries
Handle stable error codes and retry only safe failures.
Public REST errors use a stable machine-readable error.code and a human-readable error.message. Branch on the code or HTTP status, not on message text.
Canonical errors
| HTTP | Code | Meaning | Retry unchanged? |
|---|---|---|---|
| 401 | unauthorized |
Bearer token is missing or invalid | No |
| 402 | account_inactive |
An active paid account is required | No |
| 402 | quota_exhausted |
The account has no request quota remaining | No |
| 404 | not_found |
The requested job does not exist for this account | No |
| 409 | idempotency_conflict |
The key was used for different input | No |
| 422 | credentials_required |
The capability needs stored upstream credentials | No |
| 429 | rate_limited |
The account or key exceeded its current rate | Yes, after delay |
| 500 | internal_error |
Upscrape encountered an unexpected failure | Usually, with idempotency |
Capability jobs can also finish with capability- or upstream-specific error codes in the failed job representation.
When Prefer: wait=N returns a failed job inline, its HTTP status reflects the known failure class. An unrecognized terminal code returns HTTP 500; HTTP 200 is reserved for completed work and idempotent replay envelopes.
Rate limits
HTTP 429 includes a Retry-After header in seconds and error.retry_after_ms in the JSON body. Wait at least that long and add jitter before retrying.
{
"error": {
"code": "rate_limited",
"message": "rate limit exceeded",
"retry_after_ms": 1250
}
}
Safe retry policy
- Retry rate limits after the advertised delay.
- Retry transient transport failures and internal errors only with the original idempotency key.
- Poll an existing pending job instead of resubmitting it.
- Do not retry authentication, billing, credential, validation, or idempotency-conflict failures unchanged.
- Put a total deadline and attempt limit around every retry loop.
Redaction
Job failure messages are sanitized before they enter the public response. Even so, applications should avoid copying entire upstream responses into their own logs without an additional data-sensitivity review.