Docs / API Platform /Operate & reference

Errors

The bitHuman API error format, HTTP status codes, and the full error-code catalog with resolution steps.

Error response format

Every error follows the same structured envelope:

{
  "error": {
    "code": "ERROR_CODE",
    "message": "Human-readable description of what went wrong.",
    "httpStatus": 401
  },
  "status": "error",
  "status_code": 401
}

Important The HTTP transport status always matches status_code and error.httpStatus — there is no “200-on-error”. An auth failure returns HTTP 401, a validation failure returns HTTP 400, and so on. You can branch on either the HTTP status line or the parsed error.code; they never disagree.

HTTP status codes

StatusMeaningCommon cause
200SuccessRequest completed.
302RedirectNot an error — GET /v1/agent/{code}/model/download redirects to the artifact URL by default.
400Bad RequestMalformed JSON, missing required parameter (MISSING_PARAM), failed validation (VALIDATION_ERROR), or a request that can never succeed as posed (MODEL_NOT_DOWNLOADABLE).
401UnauthorizedInvalid api-secret (UNAUTHORIZED) or absent api-secret header (MISSING_AUTH).
402Payment RequiredInsufficient credits — top up to continue.
404Not FoundAgent, resource, or endpoint doesn’t exist — or a model artifact not published to the download store yet (MODEL_ARTIFACT_NOT_READY, retryable).
409ConflictThe request is valid but the agent’s state doesn’t allow it yet (MODEL_NOT_GENERATED, AGENT_NOT_READY) — a state change (generate/add the model, wait for ready) fixes it.
413Payload Too LargeFile exceeds the size limit.
415Unsupported Media TypeFile type not supported.
422Unprocessable EntityThe request is well-formed but semantically incompatible with the target model (MODEL_SUBJECT_MISMATCH, MODEL_PREREQUISITE_MISSING) — change the input or asset, not the request syntax.
429Rate LimitedToo many requests — see rate limits.
500Internal ErrorServer-side error — retry or contact support.
503Service UnavailableAll workers busy — retry with backoff. Also MODEL_NOT_YET_AVAILABLE — a second-generation family paused for your account (rare — Essence 2 / Expression 2 are GA since July 10, 2026), or a talking-video tier whose offline render worker isn’t wired yet (e.g. essence-2-max).

Error codes

Authentication

CodeHTTPResolution
UNAUTHORIZED401The api-secret header is present but invalid. Get a valid secret from Developer → API Keys.
MISSING_AUTH401The api-secret header is absent. Add it to your request.
ACCOUNT_SUSPENDED401/403Balance below the -11 suspension floor. Top up, then contact support if it persists.
INSUFFICIENT_BALANCE402Top up credits at www.bithuman.ai.

Agent operations

CodeHTTPResolution
NOT_FOUND404Returned both when no agent matches the code and when an agent has no active session for /speak / /add-context. Distinguish by the message string: "Agent not found for code: <code>" vs "No active rooms found for agent <code>".
VALIDATION_ERROR400Body failed schema validation. Include all required fields.
VIDEO_INPUT_NOT_SUPPORTED400Agent creation with a video input. Creation is image-only for every model — provide a portrait image; bitHuman generates the 10-second identity video internally so it loops seamlessly (first frame == last frame). This rejection is rolling out platform-wide (nothing charged when it fires) — never send video.
MISSING_PARAM400A required parameter was not provided.

Model errors

The model-release surfaces — creation, model add, model download, the embed-token model field, and talking video — share these codes:

CodeHTTPResolution
MODEL_NOT_GENERATED409The requested model family isn’t in the agent’s supported_models — it can’t be launched (or downloaded) as that family yet. Trained families (expression-2, essence-2-light — the standard Essence 2’s internal family name): "agent <code>'s <model> model hasn't been generated yet"add the model or create the agent with it. essence-2-max is gated on the agent’s stored identity video (generated internally by Essence creations, never uploaded; its identity prepares on demand from that video; the message keeps the internal essence-2-quality family name until the platform-side flip). Checked before any charge.
AGENT_NOT_READY409POST /v1/agent/{code}/models on an agent that is still generating or failed. Wait for the current generation to finish, or fix/re-create a failed agent first.
MODEL_SUBJECT_MISMATCH422An explicit Essence 2 creation or add whose input is not a photorealistic human subject — e.g. "essence-2 requires a photorealistic human subject; this image looks like a cartoon — use expression-2". Nothing is billed and no agent row is created. Use expression-2 for stylized/non-human subjects, or model: "auto" to route automatically. See the subject gate.
MODEL_PREREQUISITE_MISSING422A model add needs a stored asset this agent doesn’t have — a stored identity video for essence-2 (generated internally by Essence creations, never uploaded), face image for expression-2, image + voice for expression-1, stored identity video or image for essence-1. Add the missing image/voice asset, then retry.
MODEL_NOT_DOWNLOADABLE400Model download for a family with no per-identity artifact — expression-1 renders server-side from the agent’s image. A 400 because no state change can fix it (unlike the 409s).
MODEL_NOT_YET_AVAILABLE503Essence 2 / Expression 2 are GA (since July 10, 2026), so creation and model add don’t return this in normal operation — it’s the safety response if a v2 family is paused. It is also returned by talking video for a tier whose offline render worker isn’t wired yet (e.g. essence-2-max). Nothing charged; retry later or use another model (the v1 families always work).
MODEL_ARTIFACT_NOT_READY404Model download for a supported family whose artifact hasn’t been published to the download store yet. Retryable — the message carries a per-family retry hint; poll on this code.

File operations

CodeHTTPResolution
FILE_TOO_LARGE413Images 10 MB, video 100 MB, audio 50 MB, docs 10 MB.
UNSUPPORTED_TYPE415Supported: JPEG, PNG, WebP, MP4, WAV, MP3, OGG.
DOWNLOAD_FAILED400Ensure the URL is publicly accessible and returns a valid file.

Session & infrastructure

CodeHTTPResolution
RATE_LIMITED429Back off and retry. See rate limits.
SESSION_LIMIT429Concurrent-session capacity reached. Wait for an active session to end, then retry.
CONCURRENCY_LIMIT_REACHED403A new session start would exceed your plan’s concurrent avatar session allowance (enforcement rolling out). End an active session or upgrade the plan, then retry — live sessions are never cut off mid-stream by this limit.
NO_AVAILABLE_WORKERS503All workers busy. Retry with exponential backoff (up to 5 times).
INTERNAL_ERROR500Retry once. If persistent, report via Discord.

Handling errors in Python

import requests

resp = requests.post(
    "https://api.bithuman.ai/v1/agent/generate",
    headers={"api-secret": api_secret, "Content-Type": "application/json"},
    json={"prompt": "You are a helpful assistant"},
)

# The HTTP status always matches the body's status_code, so either is safe to
# branch on. On error, the body is the structured envelope: {"error": {...}}.
if resp.ok:
    body = resp.json()
    print("Agent generating:", body["data"]["agent_id"] if "data" in body else body.get("agent_id"))
elif resp.status_code in (401, 403):
    print("Auth failed. Check BITHUMAN_API_SECRET.")
elif resp.status_code == 429:
    print("Rate limited. Wait and retry with backoff.")
elif resp.status_code == 503:
    print("Workers busy. Retry in a few seconds.")
else:
    err = resp.json()["error"]
    print(f"Error {err['code']}: {err['message']}")

For 429 and 503, use exponential backoff with jitter — see rate limits for the recommended retry strategy.