Skip to content

fix: handle Pydantic BaseModel in _safe_json_serialize for telemetry#4723

Open
giulio-leone wants to merge 2 commits intogoogle:mainfrom
giulio-leone:fix/pydantic-telemetry-serialize-v2
Open

fix: handle Pydantic BaseModel in _safe_json_serialize for telemetry#4723
giulio-leone wants to merge 2 commits intogoogle:mainfrom
giulio-leone:fix/pydantic-telemetry-serialize-v2

Conversation

@giulio-leone
Copy link

Summary

Add explicit Pydantic BaseModel handling in _safe_json_serialize() in both tracing.py and lite_llm.py.

Problem

Pydantic models passed to _safe_json_serialize() are not directly JSON serializable via json.dumps(). In tracing.py, this results in the fallback <not serializable> string being recorded in telemetry spans, losing valuable debugging data. In lite_llm.py, it falls back to str(obj) which produces a less useful representation.

Fix

Before attempting json.dumps(), check if the object is a BaseModel instance and call obj.model_dump() first to convert it to a plain dict, then serialize with default=str as a safety net for nested non-serializable types.

This ensures Pydantic objects in telemetry spans and LiteLLM traces are properly serialized as structured JSON.

@google-cla
Copy link

google-cla bot commented Mar 5, 2026

Thanks for your pull request! It looks like this may be your first contribution to a Google open source project. Before we can look at your pull request, you'll need to sign a Contributor License Agreement (CLA).

View this failed invocation of the CLA check for more information.

For the most up to date status, view the checks section at the bottom of the pull request.

@gemini-code-assist
Copy link
Contributor

Summary of Changes

Hello, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request enhances the _safe_json_serialize utility function to correctly handle Pydantic BaseModel objects. By explicitly converting these models to dictionaries before serialization, it resolves issues where Pydantic objects were not properly serialized, leading to incomplete or less useful data in telemetry spans and LiteLLM traces. The change improves the fidelity of recorded data by ensuring structured JSON output for Pydantic models.

Highlights

  • Pydantic BaseModel Serialization: Implemented explicit handling for Pydantic BaseModel instances within the _safe_json_serialize() function in both tracing.py and lite_llm.py.
  • Improved Data Representation: Ensures that Pydantic models are converted to plain dictionaries using model_dump() before JSON serialization, preventing data loss and providing structured JSON output for telemetry and LiteLLM traces.

🧠 New Feature in Public Preview: You can now enable Memory to help Gemini Code Assist learn from your team's feedback. This makes future code reviews more consistent and personalized to your project's style. Click here to enable Memory in your admin console.

Changelog
  • src/google/adk/models/lite_llm.py
    • Added a check for BaseModel instances and serialized them using obj.model_dump() with default=str.
  • src/google/adk/telemetry/tracing.py
    • Introduced a check for BaseModel instances and serialized them using obj.model_dump() with default=str.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

Copy link
Contributor

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request addresses an issue with JSON serialization of Pydantic BaseModel objects by adding explicit handling for them in _safe_json_serialize. The change is applied consistently in both lite_llm.py and tracing.py, which should resolve the telemetry data loss. The approach of using model_dump() with default=str is robust. My main feedback is regarding code duplication. The same logic for handling Pydantic models is now present in two separate files. I've left a comment suggesting a refactoring to a shared utility function to improve long-term maintainability.

Comment on lines +496 to +497
if isinstance(obj, BaseModel):
return json.dumps(obj.model_dump(), default=str)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

While this correctly handles Pydantic BaseModel serialization, the same logic has been added to src/google/adk/telemetry/tracing.py. To improve maintainability and avoid code duplication, consider extracting this Pydantic-specific serialization logic into a shared utility function. This would ensure that any future changes to Pydantic serialization are made in a single place.

For example, you could create a helper in a utils module:

# in a new utils/serialization.py
from pydantic import BaseModel
import json
from typing import Any, Optional

def serialize_pydantic_model(obj: Any) -> Optional[str]:
    if isinstance(obj, BaseModel):
        return json.dumps(obj.model_dump(), default=str)
    return None

And then call it from both _safe_json_serialize functions:

# in lite_llm.py and tracing.py
from ..utils.serialization import serialize_pydantic_model

def _safe_json_serialize(obj) -> str:
    # ...
    try:
        serialized = serialize_pydantic_model(obj)
        if serialized is not None:
            return serialized
        # ... rest of the original logic
    # ...

@giulio-leone
Copy link
Author

This PR is ready for review — all CI checks pass, no merge conflicts, and all review threads have been resolved. The shared serialization utility has been extracted per review feedback. Ready to merge when approved. 🚀

giulio-leone and others added 2 commits March 5, 2026 21:43
Add explicit BaseModel handling in _safe_json_serialize() in both
tracing.py and lite_llm.py. Pydantic models are not directly JSON
serializable, so we call model_dump() first to get a plain dict before
serializing. This prevents '<not serializable>' telemetry data for
Pydantic objects.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Extract the duplicated Pydantic BaseModel serialization logic from
both lite_llm.py and tracing.py into a shared serialize_pydantic_model()
helper in utils/serialization_utils.py. This ensures future changes to
Pydantic serialization are made in a single place.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@giulio-leone giulio-leone force-pushed the fix/pydantic-telemetry-serialize-v2 branch from 7948614 to 00555fe Compare March 5, 2026 20:43
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.

1 participant