litellm - ✅(Solved) Fix [Bug]: `validate_and_fix_openai_messages` triggers pydantic serializer warnings on assistant Messages with tool_calls [1 pull requests, 1 comments, 2 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#25880Fetched 2026-04-17 08:28:21
View on GitHub
Comments
1
Participants
2
Timeline
9
Reactions
0
Author
Timeline (top)
labeled ×3referenced ×3cross-referenced ×2commented ×1

Error Message

warnings.filterwarnings('error', message='Pydantic serializer warnings')

Root Cause

validate_and_fix_openai_messages mutates a pydantic Message's tool_calls field in-place with dicts produced by jsonify_tools, then calls model_dump() on the same Message. Because the field's declared type is List[ChatCompletionMessageToolCall], pydantic's serializer emits PydanticSerializationUnexpectedValue for every tool_call in the conversation history.

Fix Action

Fixed

PR fix notes

PR #25893: fix: avoid pydantic serializer warnings in validate_and_fix_openai_messages

Description (problem / solution / changelog)

validate_and_fix_openai_messages assigned dict-shaped tool_calls back to the original pydantic Message before calling convert_to_dict/model_dump on it, so pydantic emitted PydanticSerializationUnexpectedValue for every tool_call whose declared type is List[ChatCompletionMessageToolCall].

Convert the message to a dict first, then apply jsonify_tools to the dict's tool_calls. Behavior is unchanged; only the type-mismatch serializer warning is gone.

Fixes #25880

Changed files

  • litellm/utils.py (modified, +9/-2)

Code Example

for message in messages:
    if not message.get("role"): message["role"] = "assistant"
    if message.get("tool_calls"):
        message["tool_calls"] = jsonify_tools(tools=message["tool_calls"])  # now List[dict]
    convert_msg_to_dict = cast(AllMessageValues, convert_to_dict(message))  # model_dump → warns

---

for message in messages:
    if isinstance(message, BaseModel): message = message.model_dump(exclude_none=True)
    else: message = dict(message)
    if not message.get("role"): message["role"] = "assistant"
    if message.get("tool_calls"):
        message["tool_calls"] = jsonify_tools(tools=message["tool_calls"])
    new_messages.append(cleanup_none_field_in_message(message=message))

---

import warnings, litellm
from litellm.types.utils import Message, ChatCompletionMessageToolCall
from litellm.types.utils import Function
from litellm.utils import validate_and_fix_openai_messages

warnings.filterwarnings('error', message='Pydantic serializer warnings')

tc = ChatCompletionMessageToolCall(id='toolu_1', type='function',
    function=Function(name='add', arguments='{"a":1,"b":2}'))
msg = Message(content='', role='assistant', tool_calls=[tc])

validate_and_fix_openai_messages([
    {'role': 'user', 'content': 'hi'},
    msg,
    {'role': 'tool', 'tool_call_id': 'toolu_1', 'content': '3'},
])

---

UserWarning: Pydantic serializer warnings:
  PydanticSerializationUnexpectedValue(Expected `ChatCompletionMessageToolCall` -
  serialized value may not be as expected
  [field_name='tool_calls', input_value={...}, input_type=dict])

---
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?

validate_and_fix_openai_messages mutates a pydantic Message's tool_calls field in-place with dicts produced by jsonify_tools, then calls model_dump() on the same Message. Because the field's declared type is List[ChatCompletionMessageToolCall], pydantic's serializer emits PydanticSerializationUnexpectedValue for every tool_call in the conversation history.

Location

litellm/utils.py in validate_and_fix_openai_messages:

for message in messages:
    if not message.get("role"): message["role"] = "assistant"
    if message.get("tool_calls"):
        message["tool_calls"] = jsonify_tools(tools=message["tool_calls"])  # now List[dict]
    convert_msg_to_dict = cast(AllMessageValues, convert_to_dict(message))  # model_dump → warns

jsonify_tools replaces each ChatCompletionMessageToolCall instance with a plain dict. The following convert_to_dict(message) calls message.model_dump(exclude_none=True), and pydantic warns because the runtime values no longer match the declared field type.

Suggested fix

Either:

  1. Pass a plain dict copy into jsonify_tools / convert_to_dict rather than mutating the pydantic Message in place, or
  2. Reconstruct a new Message (or just a dict) after jsonify_tools rather than assigning dicts back to message["tool_calls"].

E.g.:

for message in messages:
    if isinstance(message, BaseModel): message = message.model_dump(exclude_none=True)
    else: message = dict(message)
    if not message.get("role"): message["role"] = "assistant"
    if message.get("tool_calls"):
        message["tool_calls"] = jsonify_tools(tools=message["tool_calls"])
    new_messages.append(cleanup_none_field_in_message(message=message))

Steps to Reproduce

import warnings, litellm
from litellm.types.utils import Message, ChatCompletionMessageToolCall
from litellm.types.utils import Function
from litellm.utils import validate_and_fix_openai_messages

warnings.filterwarnings('error', message='Pydantic serializer warnings')

tc = ChatCompletionMessageToolCall(id='toolu_1', type='function',
    function=Function(name='add', arguments='{"a":1,"b":2}'))
msg = Message(content='', role='assistant', tool_calls=[tc])

validate_and_fix_openai_messages([
    {'role': 'user', 'content': 'hi'},
    msg,
    {'role': 'tool', 'tool_call_id': 'toolu_1', 'content': '3'},
])

Produces:

UserWarning: Pydantic serializer warnings:
  PydanticSerializationUnexpectedValue(Expected `ChatCompletionMessageToolCall` -
  serialized value may not be as expected
  [field_name='tool_calls', input_value={...}, input_type=dict])

Relevant log output

What part of LiteLLM is this about?

SDK (litellm Python package)

What LiteLLM version are you on ?

v1.83.0

Twitter / LinkedIn details

No response

extent analysis

TL;DR

The most likely fix is to avoid mutating the pydantic Message in-place by creating a new Message or dict after jsonify_tools instead of assigning dicts back to message["tool_calls"].

Guidance

  • The issue arises because jsonify_tools replaces ChatCompletionMessageToolCall instances with plain dicts, which don't match the declared type of tool_calls in the pydantic Message model.
  • To verify the fix, run the provided steps to reproduce and check that the PydanticSerializationUnexpectedValue warning is no longer emitted.
  • Consider reconstructing a new Message (or just a dict) after jsonify_tools to ensure the types match the expected schema.
  • Review the suggested fix in the issue, which provides an example of how to create a new message with the corrected tool_calls field.

Example

for message in messages:
    if isinstance(message, BaseModel): message = message.model_dump(exclude_none=True)
    else: message = dict(message)
    if not message.get("role"): message["role"] = "assistant"
    if message.get("tool_calls"):
        message["tool_calls"] = jsonify_tools(tools=message["tool_calls"])
    new_messages.append(cleanup_none_field_in_message(message=message))

Notes

This fix assumes that the jsonify_tools function is correctly converting the ChatCompletionMessageToolCall instances to dicts. If this function is not working as expected, additional debugging may be necessary.

Recommendation

Apply the suggested workaround by creating a new Message or dict after jsonify_tools to avoid mutating the original pydantic Message in-place. This should resolve the PydanticSerializationUnexpectedValue warning and ensure that the types match the expected schema.

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]: `validate_and_fix_openai_messages` triggers pydantic serializer warnings on assistant Messages with tool_calls [1 pull requests, 1 comments, 2 participants]