From 2964761e0c8a9b9fa6bcd0712e2702ef5c34adc2 Mon Sep 17 00:00:00 2001 From: stelloxx <41505006+stelloxx@users.noreply.github.com> Date: Wed, 8 Apr 2026 17:31:47 -0400 Subject: [PATCH] fix(auto_router): handle content-block message format in routing (#25370) When a chat message uses the OpenAI multi-modal content format (content: [{"type": "text", "text": "..."}]) instead of a plain string, message_content becomes a list. Passing a list as the embedding input causes providers that only accept strings or arrays of strings (e.g. LM Studio, OpenRouter) to return HTTP 400. Extract text parts from content blocks before passing to the semantic router so any embedding backend receives a plain string. Fixes: https://github.com/BerriAI/litellm/issues/19016 Co-authored-by: stelloxx --- litellm/router_strategy/auto_router/auto_router.py | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/litellm/router_strategy/auto_router/auto_router.py b/litellm/router_strategy/auto_router/auto_router.py index 6a786115193..be3cf9da2b8 100644 --- a/litellm/router_strategy/auto_router/auto_router.py +++ b/litellm/router_strategy/auto_router/auto_router.py @@ -120,7 +120,15 @@ class AutoRouter(CustomLogger): ) user_message: Dict[str, str] = messages[-1] - message_content: str = user_message.get("content", "") + message_content: Union[str, list] = user_message.get("content", "") + # Handle content as a list of content blocks (OpenAI multi-modal format). + # Embedding models expect a plain string; extract text parts when needed. + if isinstance(message_content, list): + message_content = " ".join( + block.get("text", "") + for block in message_content + if isinstance(block, dict) and block.get("type") == "text" + ) route_choice: Optional[Union[RouteChoice, List[RouteChoice]]] = self.routelayer( text=message_content )