statshawk
Getting started

Errors

Error envelope, status codes, and retry guidance.

Error envelope

All error responses share the same shape:

error envelope
{
  "error": {
    "code": "SNAKE_CASE_CODE",
    "message": "Human-readable explanation."
  }
}

Unlike successful responses, error bodies are not wrapped in meta — they're just the error object. Some errors include additional structured fields alongside code and messageNOT_SUPPORTED carries league and capability fields to aid feature detection. Most do not.

Status codes

StatusMeaningRetry?
400 Bad RequestInvalid parameters (bad date format, unknown stat key, bad stage selector)Fix the request
401 UnauthorizedMissing or invalid API keyCheck your key — see Auth
403 ForbiddenFree-tier key calling a paid endpoint (TIER_REQUIRES_PAID)Upgrade — don't retry
404 Not FoundResource doesn't exist (person, team, contest, competition)Don't retry
429 Too Many RequestsRate limit (RATE_LIMIT_EXCEEDED) or monthly quota (QUOTA_EXCEEDED) — branch on error.codeSee below
500 Internal Server ErrorSomething broke on our side (INTERNAL_ERROR, CACHE_ERROR)Retry once, then page support with request_id
501 Not ImplementedCapability not supported for this competition (NOT_SUPPORTED)Don't retry — check capabilities
502 Bad GatewayAn upstream data provider failed (PROVIDER_ERROR)Retry with exponential back-off
503 Service UnavailableAll providers failed, DB pool unavailable, or auth backend downRetry with exponential back-off

For the full machine-readable code catalog (UNAUTHORIZED, QUOTA_EXCEEDED, RATE_LIMIT_EXCEEDED, NOT_SUPPORTED, UNKNOWN_STAT, …), see Error codes.

Retry guidance

  • 429 — read error.code first. RATE_LIMIT_EXCEEDED means the per-second cap: back off a second or two and continue. QUOTA_EXCEEDED means the monthly unit cap: retrying won't help until the billing period resets or you upgrade (X-RateLimit-Reset carries the period-end timestamp on quota responses).
  • 502 / 503 — use exponential back-off starting at 1 s, cap at 30 s, give up after 3–5 attempts.
  • 500 — retry once; if it persists, page support with the request_id.

Everything else (400, 401, 403, 404, 501) is deterministic; retrying without changing the request, key, or plan will produce the same result.

On this page