Error Codes
Error Codes
All XCROP API errors follow a consistent JSON format. The HTTP status code indicates the error category, and the response body provides details for debugging.
Error Response Format
JSON
{ "error": "Human-readable description of the error" }
Some error responses include an additional code field (e.g. AUTH_REQUIRED) for programmatic handling.
HTTP Status Codes
| Status | Type | Description | Action |
|---|---|---|---|
| 200 | OK | Request succeeded | Process the response data |
| 400 | BAD_REQUEST | Invalid parameters or missing fields | Check request body and query params |
| 401 | UNAUTHORIZED | Missing or invalid API key | Verify your Authorization header |
| 403 | FORBIDDEN | Access denied (e.g. no X account connected) | Connect X account or check permissions |
| 404 | NOT_FOUND | Resource does not exist | Verify the username, tweet ID, or endpoint |
| 409 | CONFLICT | Duplicate resource or state conflict | Check for existing pending operations |
| 422 | UNPROCESSABLE | Request understood but cannot be processed. REPOSTS_UNREADABLE (check-retweet), REPLIES_UNREADABLE (check-reply) and POSTS_UNREADABLE (check-quote) usually mean the account is protected, suspended or withheld, so that tab cannot be read at all; X returning nothing for it is a rarer second cause. None of them are billed | Check the error code. The *_UNREADABLE codes are about the account, not your parameters. Do not retry immediately: for five minutes that handle is answered from memory without calling X. If you believe the account is readable, try again after that |
| 429 | RATE_LIMIT_EXCEEDED | Credit or per-minute limit reached | Wait for reset or upgrade plan |
| 500 | INTERNAL_ERROR | Server-side error | Retry after a short delay; contact support if persistent |
| 503 | UPSTREAM_BUSY | The upstream read could not be completed: capacity temporarily exhausted, the read timed out, or the data backend was restarting. ENDPOINT_NOT_DEPLOYED means that endpoint is not live on the backend yet | Retry after the Retry-After header (30 seconds; 600 for ENDPOINT_NOT_DEPLOYED). Not billed |
Common Error Examples
401: Missing or invalid API keyJSON
{ "error": "Authentication required. Please provide an API key or log in.", "code": "AUTH_REQUIRED" }
400: Missing required fieldJSON
{ "error": "Missing required field: query" }
429: Monthly credits used upJSON
{ "error": "Monthly credit limit reached", "code": "CREDITS_EXHAUSTED" }
Retry Strategy
For 429 and 5xx errors, implement exponential backoff:
Retry with backoffJAVASCRIPT
async function fetchWithRetry(url, options, maxRetries = 3) { for (let i = 0; i < maxRetries; i++) { const res = await fetch(url, options); if (res.ok) return res.json(); if (res.status === 429 || res.status >= 500) { const delay = Math.min(1000 * Math.pow(2, i), 30000); console.log("Retrying in " + delay + "ms..."); await new Promise(r => setTimeout(r, delay)); continue; } throw new Error("API error: " + res.status); } throw new Error("Max retries exceeded"); }
⚠
Do not retry 400, 401, 403, 404, or 422 errors: these indicate issues with your request, or with the account you asked about, that won't be resolved by retrying. None of them are billed.