Docs index: /llms.txt · every page as Markdown: add .md

‹ Platforms

Flutter errors

What BithumanAvatar.load throws, why a voice session ends, and what to do.

A failure reaches your app in one of two places: BithumanAvatar.load throws, or a running voice session ends once on errorStream. Decide on the code, never on the message, which is written for people and can change.

A network error never means the API secret is wrong. Retry it later, and do not sign the user out or ask for a new secret.

Loading an avatar

load throws BithumanModelRejected when the engine refuses the avatar file, BithumanEntitlementException when bitHuman has not said yes to this API secret for this avatar (plugin 2.6.36 or newer), and a PlatformException for everything else. The installers (downloadAgentImx, downloadExpression2Avatar, downloadExpression2Agent, downloadEssence2Bundle) throw BithumanEntitlementException too. Neither class is a PlatformException, so catch each one:

try {
  final avatar = await BithumanAvatar.load(code, engine: 'essence2', apiSecret: secret);
} on BithumanModelRejected catch (e) {
  // MODEL_REJECTED: this avatar cannot run here; show it as unavailable
} on BithumanModelPreparing catch (e) {
  // still being prepared for this device (2.6.40): show e.userMessage, load again on BithumanModelPreparing.retryDelay
} on BithumanEntitlementException catch (e) {
  // e.refused true: bitHuman said no to this secret for this avatar; do not retry with it
  // e.refused false: bitHuman could not be asked (offline, a timeout); retry when online
} on PlatformException catch (e) {
  // e.code: load_failed, load_cancelled, unsupported, detached, BAD_ARGS
}
CodePlatformsWhat happenedRetry helpsWhat to do
MODEL_REJECTED (BithumanModelRejected)Android, iOS, macOSThe engine refused the avatar file. nativeCode -4 on Essence 2: the file was published before the engine’s current version. On Android the plugin downloads the file again once before it gives up.NoShow the character as unavailable. On iOS and macOS, download the file again (GET /v1/agent/{code}/model/download).
BithumanModelPreparing (Android code model_preparing)Android, iOS, macOSThe character is still being prepared for this device: it is still training, or its on-device copy is still being built (the door answered 404 MODEL_ARTIFACT_NOT_READY). Plugin 2.6.40 and newer; earlier versions report it as BithumanEntitlementException, refused: false. Nothing is downloaded or opened.Yes, laterShow userMessage (“Preparing this character for your device…”) and load again on BithumanModelPreparing.retryDelay (30 s, 60 s, 120 s, then every 5 minutes), or use retryWhileModelPreparing. Never ask for a new API secret.
BithumanEntitlementException, refused: trueAndroid, iOS, macOSbitHuman refused this API secret for this avatar: it is another account’s private avatar, or the secret is revoked. A copy kept on the device is not opened.NoPass the API secret of the account that owns the avatar.
BithumanEntitlementException, refused: falseAndroid, iOS, macOSbitHuman could not be asked (offline, a timeout, a 5xx), and this secret has no recent yes for the kept copy: within 24 hours for an account’s own avatar, 7 days for a public one. On Android the first open of each kept avatar after updating to 2.6.36 asks once.Yes, once onlineCall load again when the device is online.
load_failedAndroidThe download or the engine failed; the message names the cause: no network, a missing or refused API secret, another account’s private avatar.Only when the cause is the network; the download keeps its bytesFix the cause. For the network, wait for it and call load again.
load_cancelledAndroidBithumanAvatar.cancelLoad(code) or BithumanAvatar.clearCredentials() stopped the load.—Nothing: the next load of that code continues the download.
unsupportedAndroid, iOS, macOSengine: names no engine, or the agent code is empty. On iOS and macOS also: Expression 2 below iOS 18 or macOS 15 (plugin 2.6.39 and newer), Essence 2 below iOS 26 or macOS 26 (the message names the version it needs), or 'essence2' in a build that does not carry the Essence 2 engine.NoPass engine: 'expression2' or 'essence2', and the agent code. Check the OS version before you download a model’s files: Expression 2 needs iOS 18 or macOS 15, Essence 2 iOS 26 or macOS 26.
detachedAndroidThe Flutter engine went away while the avatar loaded.NoLoad again from the new engine.
BAD_ARGSiOS, macOSload was called without a path.NoPass the avatar’s file (Essence 2) or folder (Expression 2).

On iOS and macOS a missing or refused API secret for a file your app downloaded itself does not throw: the avatar never becomes ready (isReady stays false). Wait on avatar.ready with a timeout, and check the secret when it expires. Always pass engine:.

Voice session

A BithumanRealtimeSession reports a failure that a retry cannot fix once, as a RealtimeSessionError on errorStream (also kept in lastError), then RealtimeStatus.error. The session then stops whole: microphone and speaker off, captions ended, streams closed. It does not reconnect; fix the cause and build a new session.

codeWhat happenedWhat to do
UNAUTHORIZEDThe relay refused the API secret at the start (HTTP 401): missing, revoked or mistyped.Use a valid API secret.
INSUFFICIENT_BALANCEThe account has no credits, at the start (HTTP 402) or when they run out during the session.Top up, then start a new session.
PAYWALLThe account has no minutes left for a voice session: its plan’s credits and its top-ups are spent (HTTP 402). bitHuman returns it for bitHuman Live sign-ins; a session on your own API secret ends with INSUFFICIENT_BALANCE instead.Choose a plan or top up, then start a new session.
FORBIDDENThe relay refused the start (HTTP 403), or bitHuman stopped the session. At the start the usual cause is the model: gpt-realtime (the session’s default before plugin 2.6.36) needs an entitlement.Pass model: 'gpt-realtime-mini'. Otherwise check the plan and the secret.
PLAN_REQUIREDThe account’s plan does not include the session. At the start the relay answers HTTP 403, which arrives as FORBIDDEN.Choose a plan.
SESSION_DURATION_LIMITThe session reached its maximum length, one hour.Start a new session.
MODEL_LOCKEDA session.update tried to change the model fixed when the session connected.Keep the model; open a new session for another.
BAD_REQUESTThe relay refused the start (HTTP 400), for example a model name it does not serve.Use gpt-realtime-mini.
MODEL_REJECTEDThe avatar’s engine refused its model file during the session.As for load, above.

A dropped connection is not on errorStream: the session reconnects, waiting 1 s and doubling up to 30 s (8 attempts), and reports RealtimeStatus.error only when they run out. A relay at capacity (HTTP 503) reports RealtimeStatus.error too; start again shortly. The relay’s codes and limits are on Realtime relay.

Android engine refusals

On Android the plugin runs the Android SDK’s engines. A refusal of the account (the plan, too many sessions, a suspended account, no credits) or an out-of-date avatar file is described, with its fix, in Android troubleshooting.