Skip to main content
When a Batch run ends with some failed tasks, you don’t scrape the whole list again. Read the failures and their error codes, then either rerun just those tasks as they are or send them again with stronger settings. Successful results carry over, so you only pay for what you retry. Uses: Batch results (GET /jobs/{id}/results?status=failed), reruns (POST /jobs/{id}/rerun?status=failed) and error codes

Ask your AI agent

Paste this prompt into a coding agent such as Claude Code or Cursor, with the Zenrows docs connected. The agent looks up the details and writes the calls.

See which tasks failed and why

Call GET /jobs/{job_id}/results with status=failed. Every row has an error object with a code you can look up in API error codes and the HTTP status of the failure. Page through with cursor until there is no next_cursor.
Python (Requests)
This job ran four URLs with plain requests (no mode=auto), so the protected page failed along with a product page that doesn’t exist:
Output
The run’s stats also count failures by reason in failure_reasons, for example {"bad_target": 2}, so you see the shape of a large run before you read every row. Decide per code:

Rerun the failures as they are

POST /jobs/{job_id}/rerun?status=failed starts a new run of the same job. Failed tasks run again with their original settings, and successful tasks carry over with their results. Use it for temporary failures. Run it once the previous run has finished.
The cURL response reports how many tasks run again and how many carry over:
The CLI run:
Here both tasks fail again, as their codes predicted: the 404 page is gone and the protected page needs stronger settings. Add ,pending to the status (include_pending=True in Python, includePending: true in Node.js) to also run tasks that never started, for example after you stopped a run.

Retry with stronger settings

A rerun keeps each task’s settings. To retry with different ones, collect the failed URLs worth retrying and submit them as a new job with stronger zenrows_params. Adaptive Stealth Mode (mode=auto) is the usual choice: it escalates to JavaScript rendering and premium proxies only where a page needs them.
Python (Requests)

Example output

The stronger-settings script on the same job skips the 404 page and resubmits the protected one:
The protected page now succeeds. Keeping the external_id on each task lets you merge the retried results back with the first job’s results.

Customize it

Troubleshooting

  • The rerun returns 409 with run_not_terminal: the previous run is still going. Wait for it to finish (job.run.wait() or zenrows batch wait), then rerun.
  • The rerun returns 409 with no_matching_tasks: no task failed in the latest run. Read the results with status=all to confirm.
  • The same tasks fail again after a rerun: their codes point to the page or the settings, not to a temporary problem. Drop 404 pages and retry the rest with stronger settings.
  • A retried task fails with REQS004 about mode=auto: the task sets js_render or premium_proxy while the job uses mode=auto. Keep one approach per task, see Use different settings for each URL in one job.
  • The whole run ended failed with a failure_reason: the account needs credits, or the key’s credit cap needs raising. Add them, then rerun with status=failed,pending.

Scrape a list of URLs

Submit thousands of URLs as one Batch job.

Use different settings for each URL in one job

Override the job’s settings for a single task.

Retry failed requests

Handle errors when you call Fetch directly.

Download all results of a job at once

Save every page to a folder or one ZIP file.