Errors & retries
v2 status codes
| Status | Meaning | Retry? |
|---|---|---|
| 200 | Request processed. Check detection. |
— |
| 400 | Image couldn't be used (invalid_image). |
No. Fix the image. |
| 401 | Missing or invalid API key (unauthorized). |
No. Fix the key. |
| 404 | Unknown model (model_not_found) or path (not_found). |
No. |
| 405 | Wrong HTTP method (method_not_allowed). |
No. |
| 422 | Request body failed validation (invalid_request). |
No. Fix the request. |
| 500 | Unexpected server error (internal_error). |
Yes, with backoff (a small number of times). |
| 429 / 502 / 503 / 504 | Returned by the hosting platform during overload, deploys, or timeouts. The body may not be JSON. | Yes, with exponential backoff. |
Recommended retry policy
- Retry only 429, 500, 502, 503, and 504, and network errors or timeouts.
- Use exponential backoff with jitter (for example 1 s, 2 s, 4 s), at most 3 attempts.
- Predictions don't change server state, so retrying is safe.
- Parse error bodies defensively: if the body isn't JSON, fall back to the HTTP status.
import random
import time
import requests
RETRYABLE = {429, 500, 502, 503, 504}
def predict(image_b64, api_key, base_url, request_id=None, attempts=3):
headers = {"api-key": api_key}
if request_id:
headers["X-Request-ID"] = request_id
for attempt in range(attempts):
try:
r = requests.post(f"{base_url}/v2/predict", headers=headers,
json={"image": image_b64}, timeout=60)
except requests.RequestException:
if attempt == attempts - 1:
raise
else:
if r.status_code not in RETRYABLE or attempt == attempts - 1:
return r
time.sleep((2 ** attempt) + random.random())
For v1 error behaviour, see API v1 errors.