Errors and how to handle them
Every error code the API returns, what it means, and whether to retry.
Errors come back as JSON with a stable code and a human-readable message:
{ "code": "INSUFFICIENT_CREDITS", "message": "You do not have enough credits to perform this action" }
Codes
| HTTP | code | Meaning | Do |
|---|---|---|---|
| 202 | TASK_STILL_PROCESSING | Not an error: the task is not finished yet. GET /task/{id} while it runs, or a POST /task / POST /map that ran past ten minutes. The body carries the task id. | Poll GET /task/{id}, or resend the POST with the same Idempotency-Key. |
| 400 | INVALID_REQUEST_BODY | The body is not JSON or a top-level field has the wrong type. | Fix the request. |
| 400 | UNSUPPORTED_TASK_TYPE | Unknown type, or a type the route does not take (crawl on /task, map on /job). | Use the right route. |
| 400 | INVALID_ATTRIBUTES | attributes do not parse or fail validation, for example an object where a string is expected (extract_selector), a js_instructions step that is not a single-action object or names an unknown action, or an unknown block_resource value. | Check the request against the reference. Do not retry unchanged. |
| 400 | MISSING_TARGET, JOB_REQUIRES_MULTIPLE_TARGETS | No url / prompt / query, or a job with fewer than two targets. | Add the target, or send one target to POST /task. |
| 400 | INVALID_TASK_ID, INVALID_JOB_ID, INVALID_CURSOR | The id or cursor in the URL is malformed. | Check the value. |
| 400 | INVALID_PROXY_TYPE, INVALID_COUNTRY | Unknown proxy plan, or a country on GET /config/proxy/asn that is not a two-letter code. | Use Basic or Premium and an ISO 3166-1 alpha-2 code. |
| 400 | INVALID_IDEMPOTENCY_KEY | Idempotency-Key empty, longer than 255 characters or sent twice. | Send one key of 1 to 255 characters. |
| 400 | INVALID_QUERY_PARAM | A list call got a limit or page that is negative or not a number, or a job_id that is not a UUID. | Fix the query string. |
| 400 | INVALID_DATE_FORMAT, INVALID_DATE_RANGE, INVALID_INTERVAL | A start_date / end_date not in YYYY-MM-DD, an end before the start (analytics: a range over 365 days), or an unknown analytics interval. | Fix the dates or pick hourly, daily, weekly or monthly. |
| 400 | INVALID_CRAWL_PATTERN, CRAWL_UNSUPPORTED_OPTION | A crawl include_paths / exclude_paths entry is not valid RE2, or result_use_ai was set on a crawl. | Fix the crawl options. |
| 401 | UNAUTHORIZED | Missing or invalid API key. | Check the header and whether the key was rotated. |
| 402 | INSUFFICIENT_CREDITS | Not enough credits for this request. | Top up, or lower max_pages on a crawl. |
| 403 | FORBIDDEN | The account behind the key is deactivated. | Contact support. |
| 404 | TASK_NOT_FOUND, JOB_NOT_FOUND, CRAWL_NOT_FOUND | Not found. Also returned for ids that belong to another account. | Check the id. |
| 409 | JOB_NOT_CANCELLABLE | The job or crawl already finished. | Nothing to cancel. |
| 409 | TASK_ALREADY_EXISTS, JOB_ALREADY_EXISTS | The create collided with an existing task or job and is not an idempotent replay. Nothing charged. | Retry the request. |
| 422 | IDEMPOTENCY_KEY_REUSED | Same Idempotency-Key sent with a different request. | Use a new key. See Retry safely with idempotency keys. |
| 429 | CONCURRENCY_LIMIT_REACHED | You already run as many tasks as your plan allows. Nothing charged. | Wait for Retry-After (1 second, sent on every route) and retry. |
| 503 | MODULE_UNAVAILABLE, ENGINE_UNAVAILABLE | The task type or AI engine was switched off by an operator; the reason is in message. Nothing charged. | Do not retry in a loop. Pick another engine or wait, and check GET /api/v1/config/capabilities. |
| 503 | API_KEY_RESET_FAILED | The key could not be rotated; the old key still works. | Retry the reset. |
| 500 | INTERNAL_ERROR | Something broke on our side. | Retry once, then contact support with the timestamp. |
Failures that are not HTTP errors
A task can answer 200 and still have status: failed. The fetch ran, the target did not cooperate. Read blocked, status_code and error in the result:
blocked: truemeans the target refused the request. The task is refunded. Retry withjs_rendering: trueor a Premium proxy.blocked: falsewithstatus: failedis usually a timeout or a proxy error. Retry once with a newIdempotency-Key. If it fails again, switch engine or proxy plan.
Read the result envelope covers every field.
Timeouts on your side
POST /task and POST /map hold the connection until the result is ready, for up to ten minutes. Set your client timeout to 120 seconds or more; browser and AI workloads can take longer. If the API answers 202 TASK_STILL_PROCESSING, poll GET /task/{id} with the id from the body. If the connection drops, resend with the same Idempotency-Key to pick up the running task instead of starting a new one.
Repeated 5xx or timeouts from the API itself
If the API, not a target site, keeps answering 5xx or timing out, check status.datafuel.ai before retrying in a loop. GET /api/v1/healthz?deep=1 answers 503 while a dependency is down. Neither needs a key. See Service status and health.