Skip to content

Comments

fix: Update AvatarSession to use FormData format for expression model…#4799

Merged
longcw merged 1 commit intolivekit:mainfrom
CathyL0:fix/custom-expression-api
Feb 13, 2026
Merged

fix: Update AvatarSession to use FormData format for expression model…#4799
longcw merged 1 commit intolivekit:mainfrom
CathyL0:fix/custom-expression-api

Conversation

@CathyL0
Copy link
Contributor

@CathyL0 CathyL0 commented Feb 12, 2026

… in custom endpoints

Copy link
Contributor

@devin-ai-integration devin-ai-integration bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Devin Review found 1 potential issue.

View 4 additional findings in Devin Review.

Open in Devin Review

Comment on lines +358 to 361
if is_custom_endpoint and self._model == "expression":
# Use FormData format for custom endpoints
# Parse async parameter from URL if present
async_mode = self._parse_async_parameter_from_url()
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔴 Custom endpoint with non-expression model sends JSON request with wrong auth headers to custom endpoint

When a custom endpoint is used with the "essence" model (or any non-"expression" model), the new condition is_custom_endpoint and self._model == "expression" evaluates to False, causing the code to fall through to the else branch which calls _send_json_request. This sends a JSON-formatted request with an api-secret header to the custom endpoint, but custom endpoints expect FormData format with Authorization: Bearer <token> headers (as implemented in _send_formdata_request).

Root Cause and Impact

Before this PR, the condition was simply if is_custom_endpoint, which correctly routed all custom endpoint requests to _send_formdata_request. The PR changed it to if is_custom_endpoint and self._model == "expression", meaning custom endpoints with model="essence" now incorrectly use _send_json_request.

The _send_json_request method (avatar.py:392-437) sends:

  • Content-Type: application/json header
  • api-secret header for authentication
  • JSON body format

But custom endpoints (avatar workers, Cerebrium deployments) expect:

  • multipart/form-data content type
  • Authorization: Bearer <token> header for authentication
  • FormData body format

Since _send_request_with_retry always posts to self._api_url (avatar.py:578), the request goes to the custom endpoint URL but with the wrong format and authentication, causing the request to fail.

Impact: All users with custom endpoints using the "essence" model will get request failures (likely 401 Unauthorized or 400 Bad Request) when trying to start a cloud avatar session.

(Refers to lines 358-369)

Prompt for agents
The condition at line 358 needs to be revised. The current logic sends custom endpoint + essence model requests through the JSON path (designed for the default BitHuman API), but the request still goes to the custom endpoint URL. There are two possible fixes depending on the intended behavior:

1. If custom endpoints with essence model should use FormData (like before the PR): revert the condition back to just `if is_custom_endpoint:` and handle the expression-specific logic inside `_send_formdata_request` instead.

2. If custom endpoints only support the expression model and essence should go through the default API: the else branch needs to use the default API URL instead of `self._api_url`, or raise an error explaining that custom endpoints only support the expression model.

The most likely correct fix is option 1 - keep using FormData for all custom endpoint requests regardless of model type, since the request URL and authentication mechanism are endpoint-specific, not model-specific.
Open in Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

@longcw longcw merged commit 859096e into livekit:main Feb 13, 2026
9 of 10 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants