Error Codes
Every error response includes a machine-readable code, a human-readable message, and a unique requestId for support.
Error Response Format
{
"success": false,
"error": {
"code": "INVALID_URL",
"message": "URL not allowed: private IP range detected.",
"details": [{ "path": "url", "message": "Must be a public URL" }]
},
"meta": {
"requestId": "req_abc123",
"timestamp": "2026-04-07T12:00:00Z"
}
}Authentication Errors
| Code | HTTP | Cause | Fix |
|---|---|---|---|
MISSING_API_KEY | 401 | No API key in request | Add Authorization: Bearer YOUR_KEY header |
INVALID_API_KEY | 401 | API key not recognized | Check your key at Dashboard → Keys |
KEY_DISABLED | 403 | API key has been revoked | Create a new key in the dashboard |
FORBIDDEN | 403 | Access denied (e.g., invalid image signature) | Verify the signed URL has not expired or been tampered with |
Validation Errors
| Code | HTTP | Cause | Fix |
|---|---|---|---|
VALIDATION_ERROR | 400 | Invalid request parameters | Check the details array for specific field errors |
INVALID_URL | 400 | URL failed validation (private IP, malformed, etc.) | Use a publicly-accessible HTTP/HTTPS URL |
INVALID_JSON | 400 | Request body is not valid JSON | Set Content-Type: application/json and validate your JSON |
UNSAFE_URL | 400 | URL flagged by Google Safe Browsing as malware/phishing | The target URL has been flagged as unsafe. Use a different URL. |
INVALID_WEBHOOK_URL | 400 | Webhook URL failed SSRF validation | Use a publicly-accessible HTTPS URL for webhooks |
Rate Limit & Usage Errors
| Code | HTTP | Cause | Fix |
|---|---|---|---|
RATE_LIMITED | 429 | Too many requests per minute | Check Retry-After and wait, or upgrade for higher throughput (Free 3 → Basic 20 → Starter 60 → Pro 300 req/min) |
USAGE_EXCEEDED | 429 | Monthly credit limit reached | Upgrade your plan or wait for monthly reset |
QUEUE_LIMIT_REACHED | 429 | Too many concurrent async jobs | Wait for active jobs to complete, or upgrade for higher limits |
BATCH_LIMIT_EXCEEDED | 400 | Batch size exceeds plan limit | Basic: 10, Starter: 25, Pro: 100, Enterprise: 500 URLs per batch (batch is a paid-plan feature) |
Plan & Feature Errors
| Code | HTTP | Cause | Fix |
|---|---|---|---|
PLAN_UPGRADE_REQUIRED | 403 | Feature requires a higher plan (e.g., geo-targeting needs Pro) | Upgrade your plan |
GEO_FEATURE_UNAVAILABLE | 422 | Unsupported parameters used with geo-targeting | Remove unsupported params (see error message for specifics) |
Capture Errors
| Code | HTTP | Cause | Fix |
|---|---|---|---|
TIMEOUT | 408 | Page load exceeded the timeout | Increase timeout (max 60s) or set bestAttempt: true |
CAPTURE_FAILED | 500 | Screenshot or PDF capture failed | Check the URL is accessible, try different parameters, or retry |
EXTRACTION_FAILED | 422 | No article-like content found to extract (POST /v1/extract) | Use a URL with readable article content, or capture an image/PDF instead |
PAYLOAD_TOO_LARGE | 413 | Rendered or extracted output exceeds the size cap (large templated HTML, Markdown, or article content) | Reduce the template data or content size; for extraction, target a smaller page |
NOT_FOUND | 404 | Route, job, batch, or image not found | Check the endpoint path and resource ID |
Watch Errors
| Code | HTTP | Cause | Fix |
|---|---|---|---|
WATCH_NOT_FOUND | 404 | Watch not found, or not owned by your account | Check the watch ID; list yours with GET /v1/watches |
WATCH_PAUSED | 409 | Ran a paused watch (POST /v1/watches/:id/run) | Resume it first (PATCH /v1/watches/:id with paused: false) |
WATCH_LIMIT_REACHED | 403 | Watch count (active + paused) exceeds your plan's limit | Delete a watch, or upgrade your plan |
WATCH_HOST_LIMIT_REACHED | 403 | More than 10 active watches aimed at one website (a separate anti-abuse cap, distinct from your plan's watch limit) | Pause/delete a watch on that host, or watch a different host |
WATCH_INTERVAL_TOO_FAST | 403 | intervalMinutes is below your plan's floor (Free 1440, Basic 180, Starter 60, Pro 30, Enterprise 5) | Use a slower interval, or upgrade your plan |
Server Errors
| Code | HTTP | Cause | Fix |
|---|---|---|---|
CONFIGURATION_ERROR | 503 | Server-side configuration issue (e.g., geo service unavailable) | Retry after a few minutes. If persistent, contact support. |
INTERNAL_ERROR | 500 | Unexpected server error | Retry the request. If persistent, contact support with the requestId. |
Handling Errors in Code
Both SDKs throw typed error objects with the error code, message, HTTP status, and request ID.
JavaScript
import { Rendex, RendexApiError } from "@copperline/rendex";
const rendex = new Rendex("YOUR_API_KEY");
try {
const { image } = await rendex.screenshot({ url: "https://example.com" });
} catch (err) {
if (err instanceof RendexApiError) {
console.error(`[${err.errorCode}] ${err.message}`);
console.error(`HTTP ${err.statusCode}, Request: ${err.requestId}`);
}
}Python
from rendex import Rendex, RendexApiError
rendex = Rendex("YOUR_API_KEY")
try:
result = rendex.screenshot("https://example.com")
except RendexApiError as err:
print(f"[{err.error_code}] {err.message}")
print(f"HTTP {err.status_code}, Request: {err.request_id}")Was this page helpful?