GuidesErrors

Errors

HTTP status codes, JSON error shapes, response headers, and when it's safe to retry.

Chuger returns standard HTTP status codes. Errors are always JSON, with a stable shape you can pattern-match in your client.

Common status codes

StatusWhen it happens
200 OKSuccessful request
202 AcceptedAsync job accepted (only /v1/content/bulk)
401 UnauthenticatedMissing or invalid API token
402 Payment RequiredNo active plan or insufficient credits
404 Not FoundPath doesn't exist, or an account-scoped resource was not found
422 Unprocessable EntityValidation failed (bad URL, missing fields, etc.)
429 Too Many RequestsRate limit or monthly quota exceeded
503 Service UnavailableRequest couldn't be fulfilled

Error shapes

Validation errors — 422

The standard validation shape:

{
  "message": "The url field is required.",
  "errors": {
    "url": ["The url field is required."]
  }
}

Authentication errors — 401

{
  "message": "Unauthenticated."
}

Plan / payment errors — 402

{
  "error": "Plan Required",
  "message": "Access to 'advanced_api' requires a higher subscription plan."
}

The stable code: "INSUFFICIENT_CREDITS" is the most reliable signal to detect — use it to trigger a top-up flow.

Rate limit errors — 429

{
  "error": "Rate limit exceeded",
  "message": "Too many requests for content endpoint. Rate limit will reset at 2026-05-13 14:01:00 UTC.",
  "details": {
    "endpoint": "content",
    "limit": 15,
    "remaining": 0,
    "reset_time": 1731600060,
    "reset_date": "2026-05-13 14:01:00 UTC"
  },
  "retry_after": 24
}

Upstream / fulfilment errors — 503

When Chuger genuinely couldn't fulfill a request — for example, the target site refused us across every fallback path — you get a plain 503:

{
  "message": "Failed to scrape the URL using available services."
}

No credits are deducted on 503 responses. You can safely retry after a short delay.

Useful headers on errors

429 responses include the same X-RateLimit-* and X-Monthly-* headers documented in Rate limits & quotas, plus Retry-After in seconds when applicable.

Handling errors in code

const res = await fetch(url, { headers });

if (res.status === 429) {
  const retryAfter = Number(res.headers.get('Retry-After') ?? 30);
  await sleep(retryAfter * 1000);
  return retry();
}

if (res.status === 402) {
  const body = await res.json();
  if (body.code === 'INSUFFICIENT_CREDITS') {
    notifyOps('Out of credits — top up at chuger.com');
  }
  throw new Error(body.message);
}

if (!res.ok) {
  throw new Error(`Chuger ${res.status}: ${await res.text()}`);
}

When to retry

StatusSafe to retry?
429Yes, after Retry-After seconds
503Yes, with backoff (failed services may recover)
5xxYes, with backoff
401, 402, 403, 404, 422No — fix the request first