Errors

Every error uses one envelope:

{ "error": { "code": "quota_exhausted", "message": "Monthly quota exceeded", "details": {} } }

Code table

HTTPcodeWhen
400bad_requestThe request is malformed or a field is invalid — the message says which. Also a pass-through model id that is :free, openrouter/*, unknown or unpriced (see Drop-in from OpenRouter)
400bad_keyInvalid document key (incl. ./..)
400already_subscribedYou already hold that subscription
401unauthenticated / key_expiredMissing, bad, or expired API key
402quota_exhausted / key_budget_exhausted / insufficient_creditMoney / quota walls — insufficient_credit is also a pass-through call whose estimated cost your credit can't cover. key_budget_exhausted means the key hit one of its spending limits; details carries period, limit_usd, spent_usd and resets_at (null for a total limit)
402elevenlabs_daily_cap_reachedElevenLabs drop-in: your account reached today's ElevenLabs limit — resets at 00:00 UTC
402passthrough_daily_cap_reachedPass-through models: your account reached today's pass-through spend limit — resets at 00:00 UTC (see Drop-in from OpenRouter)
402storage_balance_negativeObject storage: your balance is below zero — uploads pause at once, downloads after 14 days (see Object storage)
403model_not_in_planNone of your plans include the requested model
403reserved_keyWrite/delete to a reserved kb-* document
403model_denied / byok_not_enabled / forbiddenPolicy walls
403document_too_large / document_limit_reachedDocument exceeds the char cap / per-account document cap
403service_not_coveredNo active plan includes this service and extra credits can't cover it
403model_not_allowed_for_keyThe model is outside this API key's model list
403service_not_allowed_for_keyThe service is outside this API key's service list
403document_key_not_allowedThe document key is outside this API key's document filter
403elevenlabs_disabledElevenLabs drop-in: switched off — voice and model listings still answer
403voice_not_availableElevenLabs drop-in: the voice isn't a premade voice or on KhaBot's allow-list (see Drop-in from ElevenLabs — errors there use ElevenLabs' {"detail": {"status", "message"}} shape)
403storage_scope_deniedThe bucket or action is outside this API key's storage scopes
403key_not_authorizedAn account-management endpoint was called with a key that doesn't carry that permission
404model_not_foundAn unknown khabot/* model id — the full list is GET /api/v1/models
404not_availableAn OpenRouter route KhaBot doesn't offer, such as /rerank or /models/user — see Drop-in from OpenRouter
404not_foundThe requested item does not exist (e.g. an unknown media id)
404document_not_foundGET/DELETE a document that doesn't exist (not billed)
404object_not_foundObject storage: no file has that key
404page_not_foundHTML to Markdown: the page no longer exists
409bucket_exists / bucket_not_emptyObject storage: the bucket name is taken, or the bucket still holds files
413object_too_largeObject storage: a single upload over 1 GB — use a multipart upload
422cost_limit / page_blocked / page_thin / page_unsupportedHTML to Markdown page-level refusals — see HTML to Markdown
429rate_limitedYour rate limit is used up — wait retry-after seconds — or too many object-storage transfers at once
502all_providers_failedThe request could not be completed upstream — retry
503upstream_unavailableA required service is temporarily unavailable
503page_fetch_failedHTML to Markdown: the page could not be retrieved — safe to retry
503service_not_configuredThe service isn't switched on
503service_at_capacityElevenLabs drop-in: temporarily at capacity — try again later

Always branch on error.code, not the human-readable message.