Error Reference

Every error InferKit returns has three parts:

{
  "error": {
    "code": "rate_limited",                 // stable, machine-readable cause
    "message": "Rate limit exceeded",        // human-readable
    "request_id": "9f3c12a8-…-…"             // correlation id ("reference")
  }
}
  • code — branch on this in your integration. It is stable; messages may change.
  • request_id — the reference number. It appears in the end-user widget (Ref: …), in this error body, and on every server log line for that request. Quote it to InferKit support and we can pin the exact failure.

In the SDK, your onError callback (and the 'error' event) receive the normalized object { code, message, request_id, reference }. reference is the request_id when the failure reached the server, or a generated c-… id for purely client-side failures (e.g. WebGPU unavailable, network down before any request).

Who sees what

  • End user (visitor): a friendly message + Ref: <reference>. Never codes/internals.
  • Developer: the full { code, message, request_id, reference } — handle programmatically.
  • InferKit/support: request_id → exact log line (logs code + full context).

Code catalog

HTTPcodeCauseTypical action
400bad_requestmalformed requestfix the request
401invalid_api_keymissing/bad keycheck the publishable key
401invalid_tokendashboard session expiredre-authenticate
401invalid_credentialswrong email/password
401bot_challenge_requiredneeds a Turnstile sessionSDK handles automatically
402upgrade_requiredremote inference on Free tierupgrade / stay local
402quota_exceededmonthly token cap reachedupgrade or wait for reset
403forbiddenyour org role lacks this capabilityask an owner/admin
403email_not_verifiedaccount email not yet verifiedverify via the emailed link
403key_revokedkey was revokedissue a new key
403key_suspendedauto-suspended for abusereactivate in dashboard
403key_expiredrotated token past its graceuse the current key
403origin_not_allowedOrigin not in domain allowlistadd the domain
403ip_not_allowedsecret-key IP not allowlistedadd the IP
403direct_origin_blockedbypassed the edge (origin lock)call via the public hostname
403challenge_failedTurnstile verification failedretry the challenge
404not_foundno such route/resourcecheck the path
409email_in_usesignup email existslog in instead
429rate_limitedRPM / per-IP limitback off (Retry-After)
503bot_protection_unconfiguredTurnstile not set up server-sideInferKit config
503billing_unconfiguredStripe not set up server-sideInferKit config
503email_unconfiguredemail provider not set up server-sideInferKit config
503provider_unavailableupstream model errorretry; report request_id
500internal_errorunexpectedreport request_id

5xx responses return a generic message (details stay in logs, keyed by request_id). 4xx responses return a specific, safe-to-display message.

Handling examples (SDK)

InferKit.init({
  apiKey: 'ik_pub_live_…',
  onError: (e) => {
    switch (e.code) {
      case 'upgrade_required':
      case 'quota_exceeded':
        showUpgradePrompt(); break;
      case 'rate_limited':
        // back off and retry later
        break;
      default:
        console.error(`InferKit error [${e.code}] ref=${e.reference}`, e.message);
    }
  },
});

Keep this catalog in sync with packages/api/src/lib/errors.js (ERROR_CODES) and the SDK normalization in packages/sdk/src/util/errors.js.