code, and a detail sentence in a JSON body. This page maps each common code to the change that gets you the page, then puts the rules into one function you can drop into your scraper.
Uses: Fetch with Adaptive Stealth Mode (mode=auto), allowed_status_codes, the Concurrency-Limit header and the API error codes
Ask your AI agent
With the Zenrows MCP server connected to Claude, Cursor or any MCP client, paste this prompt. Your agent picks the right Zenrows tools and settings on its own.Read the error body
Every error is an RFC 7807 JSON object.code names the cause and type links to its entry in the error code reference. This request combines js_render with mode=auto on purpose, to show an error body:
cURL
code with the URL on every failure, so you can group failures by cause and apply one fix per group.
Quick reference
422: get the page with a stronger configuration
RESP001 means that attempt returned no usable content. Let Zenrows choose the configuration:
- Send
mode=auto. Adaptive Stealth Mode adds JavaScript rendering and premium proxies only when a page needs them, and bills only the configuration that succeeds. - For full control, send
js_render=trueandpremium_proxy=true, addwait_forwith a selector of the content you need, andproxy_countrywhen the site serves one region. - Retry with backoff. A 422 is retryable, and requests that don’t succeed aren’t charged.
no_data_extracted (also 422) means the page had no values for Extract’s fields. Make sure it rendered fully (js_render=true with wait_for, instead of mode=auto), or omit extract_fields. See no_data_extracted.
499: give the request time to finish
CTX0001 (HTTP 499) means your client closed the connection before Zenrows returned the page, usually because the client’s timeout fired. Set the timeout to 180 seconds or more on every Fetch call, for example requests.get(..., timeout=180) in Python or AbortSignal.timeout(180_000) in Node.js. Requests that end in 499 aren’t charged.
429: match your plan’s concurrency
AUTH006 means more requests were in flight than your plan runs at once. Every response carries Concurrency-Limit and Concurrency-Remaining headers. Size your worker pool to the limit:
Python (Requests)
402: check credits and caps
AUTH004 means the plan’s credits for this billing period are used. AUTH014 means this API key reached a credit cap you set, while your other keys keep working. Check where you stand, free and without using a concurrency slot:
cURL
usage_credits, credit_limit, usage_percent, period_ends_at and, under api_key.caps, any caps on this key. To continue right away, top up on the Billing page, upgrade on the Plans page, or raise the key’s cap on the API keys page. See Track usage and control spend.
413: ask for the part of the page you need
RESP005 means the page is larger than one response carries. Request less of it:
If you use
json_response=true, its captured network calls count toward the size too: remove it when you don’t need them. More strategies: Response too large.
400 and 401: correct the request
These return the same answer until the request changes, so fix and resend instead of retrying.REQS004: a parameter value or the URL is invalid. Thedetailnames it. Two common ones:js_renderorpremium_proxysent withmode=auto(keep one approach), and a target URL that isn’t URL-encoded.REQS002: the domain needs JavaScript rendering or premium proxies. Sendmode=autoand Zenrows applies them.RESP004:css_extractorisn’t valid JSON or has a malformed selector. Validate it withjson.dumpson a dict.AUTH001,AUTH002,AUTH003: the key is missing or not recognized. Copy it again from the API keys page and send it asapikey.
404 and 410: handle pages the target removed
RESP002 means the target site itself answered 404: the page is gone, so drop or fix the URL. To receive the target’s own error page as content instead of an error, add allowed_status_codes=404,410. The response is then 200 and the target’s status is in the Zr-Status-Code header. Like every 404 and 410, these responses are billed as successful requests (see Pricing):
cURL
RESP007 (also 404) means the domain doesn’t resolve: check the hostname for typos.
Handle every code in one function
This function sendsmode=auto, retries the retryable statuses with backoff, treats pages the target removed as “gone”, and raises with the code, detail and docs link for anything that needs a change:
Python (Requests)
Example output
js_render on top of mode=auto on purpose, to show how a request that needs a fix surfaces.
Customize it
Related recipes
Retry failed requests
Backoff, jitter and SDK retries in Python and Node.js.
Track usage and control spend
Read per-request cost and set credit caps.
Scrape pages protected by anti-bot systems
Let Adaptive Stealth Mode pick the right configuration per page.
Run many requests concurrently
Use your plan’s concurrency to its full extent.