From a45c874d20336cdcb02d93fc2e71b8751fc11d18 Mon Sep 17 00:00:00 2001 From: Safwan Erooth Date: Fri, 24 Jul 2026 12:19:49 +0400 Subject: [PATCH] fix(trim_messages): handle list-type content on system messages trim_messages() built the trimmed system prompt by doing system_message += message["content"] for every system-role message, assuming content is always a plain string. OpenAI/Anthropic-style multi-part content (content: [{"type": "text", "text": "..."}]) is a valid, common message shape, and this crashed with: TypeError: can only concatenate str (not "list") to str Handle both shapes: strings are appended as before; list content is walked and any {"type": "text"} parts' text is appended, matching how other content-part handling in the codebase treats this format. Found via real-world load testing of a Frappe-based app hitting this frequently under concurrent load with varied prompt shapes (888-1300+ occurrences in a single 50-minute test window). Verified: a system message with list-type content no longer crashes trim_messages() and produces the expected joined system_message; a plain string-content system message is unaffected (no regression). --- litellm/utils.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/litellm/utils.py b/litellm/utils.py index a11c5500503..d944bb8293c 100644 --- a/litellm/utils.py +++ b/litellm/utils.py @@ -6806,7 +6806,13 @@ def trim_messages( for message in messages: if message["role"] == "system": system_message += "\n" if system_message else "" - system_message += message["content"] + content = message.get("content", "") + if isinstance(content, str): + system_message += content + elif isinstance(content, list): + for part in content: + if isinstance(part, dict) and part.get("type") == "text": + system_message += part.get("text", "") ## Handle Tool Call ## - check if last message is a tool response, return as is - https://github.com/BerriAI/litellm/issues/4931 tool_messages = []