litellm - ✅(Solved) Fix [Bug]: TypeError: can only concatenate list (not "str") to list in map_system_message_pt when routing Anthropic-format messages to ChatGPT provider [1 pull requests, 1 participants]

Official PRs (…)
ON THIS PAGE

Recommended Tools

×6

Utilities matched from this issue’s tags and category — try them while you read without losing context.

GitHub issue graph ai analysis

Paste a GitHub issue URL. We fetch that issue, discover linked issues from bodies/comments/timeline, collect linked pull requests, and produce a structured English report.

The report is written in English Markdown for sharing and archival.

Helpful · Quick feedback

Loading…
GitHub stats
BerriAI/litellm#23757Fetched 2026-04-08 00:49:19
View on GitHub
Comments
0
Participants
1
Timeline
7
Reactions
0
Participants
Timeline (top)
labeled ×4referenced ×2cross-referenced ×1

Error Message

 File "/usr/lib/python3.13/site-packages/litellm/litellm_core_utils/prompt_templates/factory.py", line 110, in
 map_system_message_pt
     next_m["content"] = m["content"] + " " + next_m["content"]
                         ~~~~~~~~~~~~~^~~~~
 TypeError: can only concatenate list (not "str") to list

Root Cause

In litellm/litellm_core_utils/prompt_templates/factory.py line 110:

next_m["content"] = m["content"] + " " + next_m["content"]

This line assumes both m["content"] and next_m["content"] are strings. However, when the request originates from the Anthropic pass-through endpoint, the adapter converts Anthropic-format messages to OpenAI completion format, and the content field can be a list of content blocks (e.g., [{"type": "text", "text": "..."}]) rather than a plain string.

Fix Action

Fix / Workaround

  • LiteLLM version: v1.82.0
  • Docker image tag: main-v1.82.0-stable.patch5 (litellm-database, deployed via Helm)
  • Python: 3.13
  • Client: Claude Code (sends requests via Anthropic /v1/messages format)
  • Provider: chatgpt/gpt-5.4

PR fix notes

PR #23782: fix(factory): handle list content in map_system_message_pt

Description (problem / solution / changelog)

Summary

Fixes #23757

When using the Anthropic pass-through endpoint (/v1/messages) to route requests to a model with supports_system_message: false, map_system_message_pt crashes with TypeError: can only concatenate list (not "str") to list because it assumes message content is always a string.

However, the Anthropic adapter converts messages to OpenAI format with content as a list of content blocks (e.g., [{"type": "text", "text": "..."}]).

Changes

  • Add _get_content_as_str() helper that normalizes both str and list content to a string before merging, using the existing convert_content_list_to_str utility
  • Update all content access in map_system_message_pt to go through the helper
  • Add 3 test cases: list content merge, mixed str/list merge, and list content as last message

Test Plan

# System + user both with list content
messages = [
    {"role": "system", "content": [{"type": "text", "text": "You are helpful."}]},
    {"role": "user", "content": [{"type": "text", "text": "Hello!"}]},
]
new_messages = map_system_message_pt(messages=messages)
assert len(new_messages) == 1
assert new_messages[0]["role"] == "user"
assert "You are helpful." in new_messages[0]["content"]
assert "Hello!" in new_messages[0]["content"]

Changed files

  • litellm/litellm_core_utils/prompt_templates/factory.py (modified, +42/-31)
  • tests/llm_translation/test_optional_params.py (modified, +84/-0)

Code Example

File "/usr/lib/python3.13/site-packages/litellm/litellm_core_utils/prompt_templates/factory.py", line 110, in
 map_system_message_pt
     next_m["content"] = m["content"] + " " + next_m["content"]
                         ~~~~~~~~~~~~~^~~~~
 TypeError: can only concatenate list (not "str") to list

---

model_list:
   - model_name: chatgpt-gpt-5.4
     model_info:
       mode: responses
     litellm_params:
       model: chatgpt/gpt-5.4
       supports_system_message: false

 litellm_settings:
   drop_params: true

---

16:12:41 - LiteLLM Proxy:ERROR: endpoints.py:121 - litellm.proxy.proxy_server.anthropic_response(): Exception occured - litellm.APIC
Available Model Group Fallbacks=None LiteLLM Retried: 2 times, LiteLLM Max Retries: 2
Traceback (most recent call last):
  File "/usr/lib/python3.13/site-packages/litellm/main.py", line 1425, in completion
    messages = map_system_message_pt(messages=messages)
  File "/usr/lib/python3.13/site-packages/litellm/litellm_core_utils/prompt_templates/factory.py", line 110, in map_system_message_p
    next_m["content"] = m["content"] + " " + next_m["content"]
                        ~~~~~~~~~~~~~^~~~~
TypeError: can only concatenate list (not "str") to list

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/usr/lib/python3.13/site-packages/litellm/proxy/anthropic_endpoints/endpoints.py", line 53, in anthropic_response
    result = await base_llm_response_processor.base_process_llm_request(
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    ...<16 lines>...
    )
    ^
  File "/usr/lib/python3.13/site-packages/litellm/proxy/common_request_processing.py", line 886, in base_process_llm_request
    responses = await llm_responses
                ^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/site-packages/litellm/router.py", line 4709, in async_wrapper
    return await self._ageneric_api_call_with_fallbacks(
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    ...<2 lines>...
    )
    ^
  File "/usr/lib/python3.13/site-packages/litellm/router.py", line 3458, in _ageneric_api_call_with_fallbacks
    raise e
  File "/usr/lib/python3.13/site-packages/litellm/router.py", line 3445, in _ageneric_api_call_with_fallbacks
    response = await self.async_function_with_fallbacks(**kwargs)
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/site-packages/litellm/router.py", line 5111, in async_function_with_fallbacks
    return await self.async_function_with_fallbacks_common_utils(
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    ...<8 lines>...
    )
    ^
  File "/usr/lib/python3.13/site-packages/litellm/router.py", line 5068, in async_function_with_fallbacks_common_utils
    raise original_exception
  File "/usr/lib/python3.13/site-packages/litellm/router.py", line 5102, in async_function_with_fallbacks
    response = await self.async_function_with_retries(*args, **kwargs)
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/site-packages/litellm/router.py", line 5343, in async_function_with_retries
    raise original_exception
  File "/usr/lib/python3.13/site-packages/litellm/router.py", line 5208, in async_function_with_retries
    response = await self.make_call(original_function, *args, **kwargs)
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/site-packages/litellm/router.py", line 5354, in make_call
    response = await response
               ^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/site-packages/litellm/router.py", line 3570, in _ageneric_api_call_with_fallbacks_helper
    raise e
  File "/usr/lib/python3.13/site-packages/litellm/router.py", line 3556, in _ageneric_api_call_with_fallbacks_helper
    response = await response  # type: ignore
               ^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/site-packages/litellm/utils.py", line 2041, in wrapper_async
    raise e
  File "/usr/lib/python3.13/site-packages/litellm/utils.py", line 1862, in wrapper_async
    result = await original_function(*args, **kwargs)
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/site-packages/litellm/llms/anthropic/experimental_pass_through/messages/handler.py", line 187, in anthropic_messages
    response = await init_response
               ^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/site-packages/litellm/llms/anthropic/experimental_pass_through/adapters/handler.py", line 233, in async_anthropic_messages_handler
    completion_response = await litellm.acompletion(**completion_kwargs)
                          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/site-packages/litellm/utils.py", line 2041, in wrapper_async
    raise e
  File "/usr/lib/python3.13/site-packages/litellm/utils.py", line 1862, in wrapper_async
    result = await original_function(*args, **kwargs)
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/site-packages/litellm/main.py", line 632, in acompletion
    raise exception_type(
    ...<5 lines>...
    )
  File "/usr/lib/python3.13/site-packages/litellm/main.py", line 605, in acompletion
    init_response = await loop.run_in_executor(None, func_with_context)
                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/concurrent/futures/thread.py", line 59, in run
    result = self.fn(*self.args, **self.kwargs)
  File "/usr/lib/python3.13/site-packages/litellm/utils.py", line 1418, in wrapper
    result = original_function(*args, **kwargs)
  File "/usr/lib/python3.13/site-packages/litellm/main.py", line 4320, in completion
    raise exception_type(
          ~~~~~~~~~~~~~~^
        model=model,
        ^^^^^^^^^^^^
    ...<3 lines>...
        extra_kwargs=kwargs,
        ^^^^^^^^^^^^^^^^^^^^
    )
    ^
  File "/usr/lib/python3.13/site-packages/litellm/litellm_core_utils/exception_mapping_utils.py", line 2403, in exception_type
    raise e  # it's already mapped
    ^^^^^^^
  File "/usr/lib/python3.13/site-packages/litellm/litellm_core_utils/exception_mapping_utils.py", line 608, in exception_type
    raise APIConnectionError(
    ...<7 lines>...
    )
litellm.exceptions.APIConnectionError: litellm.APIConnectionError: APIConnectionError: ChatgptException - can only concatenate list (not "str") to list. Received Model Group=chatgpt-gpt-5.4
Available Model Group Fallbacks=None LiteLLM Retried: 2 times, LiteLLM Max Retries: 2
RAW_BUFFERClick to expand / collapse

Check for existing issues

  • I have searched the existing issues and checked that my issue is not a duplicate.

What happened?

Bug Description

When using the Anthropic pass-through endpoint (/v1/messages) to route requests to a chatgpt/* model with supports_system_message: false, map_system_message_pt crashes with a TypeError because it assumes message content is always a str, but the Anthropic adapter passes content as a list of content blocks.

Environment

  • LiteLLM version: v1.82.0
  • Docker image tag: main-v1.82.0-stable.patch5 (litellm-database, deployed via Helm)
  • Python: 3.13
  • Client: Claude Code (sends requests via Anthropic /v1/messages format)
  • Provider: chatgpt/gpt-5.4

Error

 File "/usr/lib/python3.13/site-packages/litellm/litellm_core_utils/prompt_templates/factory.py", line 110, in
 map_system_message_pt
     next_m["content"] = m["content"] + " " + next_m["content"]
                         ~~~~~~~~~~~~~^~~~~
 TypeError: can only concatenate list (not "str") to list

Root Cause

In litellm/litellm_core_utils/prompt_templates/factory.py line 110:

next_m["content"] = m["content"] + " " + next_m["content"]

This line assumes both m["content"] and next_m["content"] are strings. However, when the request originates from the Anthropic pass-through endpoint, the adapter converts Anthropic-format messages to OpenAI completion format, and the content field can be a list of content blocks (e.g., [{"type": "text", "text": "..."}]) rather than a plain string.

Call chain:

  1. anthropic_endpoints/endpoints.py → anthropic_messages_handler
  2. → litellm.acompletion() (converts to OpenAI completion)
  3. → completion() → map_system_message_pt() (because supports_system_message=false)
  4. → TypeError at content concatenation

Expected Behavior

map_system_message_pt should handle both str and list content formats when merging system messages into the next message.

Steps to Reproduce

  1. Configure LiteLLM proxy with a ChatGPT provider model:
 model_list:
   - model_name: chatgpt-gpt-5.4
     model_info:
       mode: responses
     litellm_params:
       model: chatgpt/gpt-5.4
       supports_system_message: false

 litellm_settings:
   drop_params: true
  1. Send a request via the Anthropic pass-through endpoint (/v1/messages) — e.g., from Claude Code configured to use LiteLLM as a proxy.
  2. The request includes a system message, which triggers map_system_message_pt to merge it into the next user message.

Relevant log output

16:12:41 - LiteLLM Proxy:ERROR: endpoints.py:121 - litellm.proxy.proxy_server.anthropic_response(): Exception occured - litellm.APIC
Available Model Group Fallbacks=None LiteLLM Retried: 2 times, LiteLLM Max Retries: 2
Traceback (most recent call last):
  File "/usr/lib/python3.13/site-packages/litellm/main.py", line 1425, in completion
    messages = map_system_message_pt(messages=messages)
  File "/usr/lib/python3.13/site-packages/litellm/litellm_core_utils/prompt_templates/factory.py", line 110, in map_system_message_p
    next_m["content"] = m["content"] + " " + next_m["content"]
                        ~~~~~~~~~~~~~^~~~~
TypeError: can only concatenate list (not "str") to list

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/usr/lib/python3.13/site-packages/litellm/proxy/anthropic_endpoints/endpoints.py", line 53, in anthropic_response
    result = await base_llm_response_processor.base_process_llm_request(
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    ...<16 lines>...
    )
    ^
  File "/usr/lib/python3.13/site-packages/litellm/proxy/common_request_processing.py", line 886, in base_process_llm_request
    responses = await llm_responses
                ^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/site-packages/litellm/router.py", line 4709, in async_wrapper
    return await self._ageneric_api_call_with_fallbacks(
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    ...<2 lines>...
    )
    ^
  File "/usr/lib/python3.13/site-packages/litellm/router.py", line 3458, in _ageneric_api_call_with_fallbacks
    raise e
  File "/usr/lib/python3.13/site-packages/litellm/router.py", line 3445, in _ageneric_api_call_with_fallbacks
    response = await self.async_function_with_fallbacks(**kwargs)
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/site-packages/litellm/router.py", line 5111, in async_function_with_fallbacks
    return await self.async_function_with_fallbacks_common_utils(
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    ...<8 lines>...
    )
    ^
  File "/usr/lib/python3.13/site-packages/litellm/router.py", line 5068, in async_function_with_fallbacks_common_utils
    raise original_exception
  File "/usr/lib/python3.13/site-packages/litellm/router.py", line 5102, in async_function_with_fallbacks
    response = await self.async_function_with_retries(*args, **kwargs)
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/site-packages/litellm/router.py", line 5343, in async_function_with_retries
    raise original_exception
  File "/usr/lib/python3.13/site-packages/litellm/router.py", line 5208, in async_function_with_retries
    response = await self.make_call(original_function, *args, **kwargs)
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/site-packages/litellm/router.py", line 5354, in make_call
    response = await response
               ^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/site-packages/litellm/router.py", line 3570, in _ageneric_api_call_with_fallbacks_helper
    raise e
  File "/usr/lib/python3.13/site-packages/litellm/router.py", line 3556, in _ageneric_api_call_with_fallbacks_helper
    response = await response  # type: ignore
               ^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/site-packages/litellm/utils.py", line 2041, in wrapper_async
    raise e
  File "/usr/lib/python3.13/site-packages/litellm/utils.py", line 1862, in wrapper_async
    result = await original_function(*args, **kwargs)
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/site-packages/litellm/llms/anthropic/experimental_pass_through/messages/handler.py", line 187, in anthropic_messages
    response = await init_response
               ^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/site-packages/litellm/llms/anthropic/experimental_pass_through/adapters/handler.py", line 233, in async_anthropic_messages_handler
    completion_response = await litellm.acompletion(**completion_kwargs)
                          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/site-packages/litellm/utils.py", line 2041, in wrapper_async
    raise e
  File "/usr/lib/python3.13/site-packages/litellm/utils.py", line 1862, in wrapper_async
    result = await original_function(*args, **kwargs)
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/site-packages/litellm/main.py", line 632, in acompletion
    raise exception_type(
    ...<5 lines>...
    )
  File "/usr/lib/python3.13/site-packages/litellm/main.py", line 605, in acompletion
    init_response = await loop.run_in_executor(None, func_with_context)
                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/concurrent/futures/thread.py", line 59, in run
    result = self.fn(*self.args, **self.kwargs)
  File "/usr/lib/python3.13/site-packages/litellm/utils.py", line 1418, in wrapper
    result = original_function(*args, **kwargs)
  File "/usr/lib/python3.13/site-packages/litellm/main.py", line 4320, in completion
    raise exception_type(
          ~~~~~~~~~~~~~~^
        model=model,
        ^^^^^^^^^^^^
    ...<3 lines>...
        extra_kwargs=kwargs,
        ^^^^^^^^^^^^^^^^^^^^
    )
    ^
  File "/usr/lib/python3.13/site-packages/litellm/litellm_core_utils/exception_mapping_utils.py", line 2403, in exception_type
    raise e  # it's already mapped
    ^^^^^^^
  File "/usr/lib/python3.13/site-packages/litellm/litellm_core_utils/exception_mapping_utils.py", line 608, in exception_type
    raise APIConnectionError(
    ...<7 lines>...
    )
litellm.exceptions.APIConnectionError: litellm.APIConnectionError: APIConnectionError: ChatgptException - can only concatenate list (not "str") to list. Received Model Group=chatgpt-gpt-5.4
Available Model Group Fallbacks=None LiteLLM Retried: 2 times, LiteLLM Max Retries: 2

What part of LiteLLM is this about?

Proxy

What LiteLLM version are you on ?

v1.82.0

Twitter / LinkedIn details

https://www.linkedin.com/in/iamjjanga

extent analysis

Fix Plan

To fix the issue, we need to modify the map_system_message_pt function in litellm/litellm_core_utils/prompt_templates/factory.py to handle both string and list content formats.

Here are the steps:

  • Check the type of m["content"] and next_m["content"] before concatenation.
  • If either of them is a list, extract the text from the list and concatenate it with the other content.

Code Changes

def map_system_message_pt(messages):
    # ...
    for m, next_m in zip(messages, messages[1:]):
        if isinstance(m["content"], list) and isinstance(next_m["content"], list):
            # Both are lists, extract text and concatenate
            m_text = "".join([c["text"] for c in m["content"] if c["type"] == "text"])
            next_m_text = "".join([c["text"] for c in next_m["content"] if c["type"] == "text"])
            next_m["content"] = [{"type": "text", "text": m_text + " " + next_m_text}]
        elif isinstance(m["content"], list):
            # m["content"] is a list, extract text and concatenate with next_m["content"]
            m_text = "".join([c["text"] for c in m["content"] if c["type"] == "text"])
            next_m["content"] = m_text + " " + next_m["content"]
        elif isinstance(next_m["content"], list):
            # next_m["content"] is a list, extract text and concatenate with m["content"]
            next_m_text = "".join([c["text"] for c in next_m["content"] if c["type"] == "text"])
            next_m["content"] = m["content"] + " " + next_m_text
        else:
            # Both are strings, concatenate directly
            next_m["content"] = m["content"] + " " + next_m["content"]
    # ...

Verification

To verify the fix, send a request via the Anthropic pass-through endpoint with a system message and check that the response does not contain any errors. The map_system_message_pt function should now correctly handle both string and list content formats.

Extra Tips

  • Make sure to test the fix with different types of content (strings and lists) to ensure it works correctly in all cases.
  • Consider adding additional error handling to handle cases where the content is not in the expected format.

Vote matrix · Quick signals

Works
Did the solution work? Tap to confirm.
Easy Fix
Was it a quick fix?
Time Saver
Did it save you time?
Blocking
Was it severely blocking?
Common Issue
Are others likely hitting this too?
Flaky / Intermittent
Is it intermittent?
Verified / Reproducible
Can you reproduce it reliably?
Loading…

Still need to ship something?

×6

Another batch ranked right after the header list — different links, same matching logic.

Back to top recommendations

TRENDING

litellm - ✅(Solved) Fix [Bug]: TypeError: can only concatenate list (not "str") to list in map_system_message_pt when routing Anthropic-format messages to ChatGPT provider [1 pull requests, 1 participants]