*Response. Automatic retries only apply to the second kind.
Basic usage
Retries are off by default (maxRetryCount is 0). Pass WithMaxRetryCount to turn them on:
WithMaxRetryCount(3), a failed request is retried up to 3 additional times before the SDK returns the last response or error it received.
When to enable retries
Enable retries (2 to 3 is a reasonable starting point) whenever you’re running requests at scale or in production, anywhere a transient429 or 500 shouldn’t fail your whole job. Leave retries off (the default) for quick one-off scripts or debugging, where you’d rather see the raw failure immediately.
Which failures get retried
The SDK retries a request when either of these is true:- The request failed at the network level (DNS failure, connection reset, timeout), regardless of status code.
- The response came back with one of these status codes:
| Status code | Meaning |
|---|---|
422 | Unprocessable Entity |
429 | Too Many Requests |
500 | Internal Server Error |
WithRetryWaitTime as a starting point (default 5 seconds), doubling on each subsequent attempt, capped at WithRetryMaxWaitTime (default 30 seconds):
Handling failures
- HTTP error status
- SDK and network errors
Even after retries are exhausted, the SDK returns a
*Response with err == nil. It doesn’t turn a non-2xx status into a Go error on its own. Always check the response before trusting its content:The four SDK error types
| Error type | When it happens |
|---|---|
NotConfiguredError | No API key was set (neither WithAPIKey nor ZENROWS_API_KEY). |
InvalidHTTPMethodError | You called Scrape with a method other than GET, POST, or PUT. |
InvalidTargetURLError | The target URL is empty or fails to parse; wraps the underlying url.Parse error via Unwrap(). |
InvalidParameterError | A RequestParameters field fails validation, for example, ScreenshotQuality outside 1 to 100, or Screenshot: false combined with ScreenshotFullPage: true. |
InvalidTargetURLError supports errors.Unwrap so you can inspect the underlying parse error with errors.As or errors.Is.
Troubleshooting
- Response still fails after retries are exhausted: Check
response.StatusCode()and look it up in API Error Codes. Some failures, like an invalid API key, aren’t fixed by retrying. - Getting
InvalidParameterErrorfor a parameter you didn’t set: SeveralRequestParametersfields depend on each other, for example,ScreenshotFullPagerequiresScreenshot: true, andWaitForSelectorrequiresJSRender: true. CheckValidate()’s rules in the SDK source if the message isn’t specific enough. 429errors even with retries enabled: You’re likely exceeding your plan’s concurrency limit, not hitting a one-off rate limit. See Concurrency.- Retries seem to take a long time: That’s the doubling backoff by design, capped at
WithRetryMaxWaitTime. LowerWithMaxRetryCountorWithRetryMaxWaitTimeif latency matters more than success rate.
Pricing
Retried attempts that fail are not billed. Only the final successful response counts:| Configuration | Cost multiplier vs. basic |
|---|---|
| Basic request | 1x |
JSRender: true | 5x |
UsePremiumProxies: true | 10x |
JSRender: true + UsePremiumProxies: true | 25x |
404 and 410 responses count as successful and are billed, since the request itself completed correctly.FAQ
What's the default number of retries?
What's the default number of retries?
Zero. Retries are disabled unless you explicitly pass
WithMaxRetryCount(n) with n > 0.Which status codes trigger an automatic retry?
Which status codes trigger an automatic retry?
422, 429, and 500, plus any network-level failure. 502, 503, and 504 are not retried automatically.Does the SDK ever return a Go error for a non-2xx response?
Does the SDK ever return a Go error for a non-2xx response?
No. A non-2xx HTTP response is still a successful round trip from the SDK’s point of view, it returns a
*Response with err == nil. Check response.IsError() or response.StatusCode() yourself.Look up a specific error code
For a full breakdown of ZenRows error codes (likeAUTH002 or RESP001) and how to resolve each one, see the API Error Codes reference.