Skip to content

fix(utils): normalize list content strings to OpenAI text parts#7

Open
lkapadiya-DO wants to merge 2 commits into
litellm_internal_stagingfrom
lkapadiya/add-normalize-content
Open

fix(utils): normalize list content strings to OpenAI text parts#7
lkapadiya-DO wants to merge 2 commits into
litellm_internal_stagingfrom
lkapadiya/add-normalize-content

Conversation

@lkapadiya-DO
Copy link
Copy Markdown
Collaborator

Relevant issues

Fixes an observed issue where sending an array of strings in the content block (e.g. ["what is the capital of France?"]) causes an internal AttributeError: 'str' object has no attribute 'get'. This previously bubbled up as a 500 Internal Server Error, confusingly attaching the extracted llm_provider to the crash response.

Also list content can include Pydantic BaseModel parts (not only strings/dicts), and invalid items (null, integers) should fail fast instead of passing through to downstream .get() calls.

Linear ticket

Pre-Submission checklist

Please complete all items before asking a LiteLLM maintainer to review your PR

  • I have Added testing in the tests/test_litellm/ directory, Adding at least 1 test is a hard requirement - see details
  • My PR passes all unit tests on make test-unit
  • My PR's scope is as isolated as possible, it only solves 1 specific problem
  • I have requested a Greptile review by commenting @greptileai and received a Confidence Score of at least 4/5 before requesting a maintainer review

Delays in PR merge?

If you're seeing a delay in your PR being merged, ping the LiteLLM Team on Slack (#pr-review).

CI (LiteLLM team)

CI status guideline:

  • 50-55 passing tests: main is stable with minor issues.
  • 45-49 passing tests: acceptable but needs attention
  • <= 40 passing tests: unstable; be careful with your merges and assess the risk.
  • Branch creation CI run
    Link:

  • CI run for the last commit
    Link:

  • Merge / cherry-pick CI run
    Links:

Screenshots / Proof of Fix

Local manual verification
From the repo root, run:

cd litellm
uv sync --dev

uv run python <<'PY'
from litellm.utils import validate_and_fix_openai_messages

out = validate_and_fix_openai_messages(
    [{"role": "user", "content": ["what is the capital of France?"]}]
)
print("Case A:", out[0]["content"])

out = validate_and_fix_openai_messages(
    [{"role": "user", "content": [
        "some text",
        {"type": "image_url", "image_url": {"url": "https://example.com/x.png"}},
    ]}]
)
print("Case B:", out[0]["content"])

try:
    validate_and_fix_openai_messages([{"role": "user", "content": [None]}])
except TypeError as e:
    print("Case D OK:", e)
PY

Expected output:

Case A: [{'type': 'text', 'text': 'what is the capital of France?'}]
Case B: [{'type': 'text', 'text': 'some text'}, {'type': 'image_url', 'image_url': {'url': 'https://example.com/x.png'}}]
Case D OK: Invalid message type: <class 'NoneType'>. Expected dict or Pydantic model.

Before:
Sending an array of strings (e.g. "content": ["what is the capital of France?"]) resulted in an internal crash that returned a 500 error containing internal proxy metadata:

{
  "error": {
    "message": "'str' object has no attribute 'get'",
    "type": "server_error",
    "param": null,
    "code": null,
    "llm_provider": "openai"
  }
}

After:
The array of strings is normalized into the OpenAI multimodal dict format before downstream processing:
"content": [{"type": "text", "text": "what is the capital of France?"}]

(Tests passing successfully locally — pytest + manual script above)

Type

🐛 Bug Fix

Changes

  1. Updated validate_and_fix_openai_messages in litellm/utils.py to normalize list content for all messages (after tool_calls handling, before convert_to_dict):
  • str → {"type": "text", "text": item}
  • dict → unchanged (e.g. existing image_url parts)
  • other (e.g. Pydantic BaseModel) → convert_to_dict(item) via model_dump()
  • invalid items (null, int, etc.) → TypeError at validation time (fail fast)
  1. Added pytest coverage in tests/test_litellm/test_utils.py:
  • test_normalize_array_of_strings_in_content
  • test_normalize_pydantic_content_part_in_content
  • test_normalize_invalid_content_item_raises_type_error (parametrized)

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