fix(core): improve error message for non-JSON-serializable tool schemas (#34376)

This commit is contained in:
Tanzim Hossain Romel
2026-02-23 04:32:00 +06:00
committed by GitHub
parent d6e46bb4b0
commit 2d1492a864
2 changed files with 57 additions and 8 deletions

View File

@@ -22,6 +22,7 @@ from typing import (
import typing_extensions
from pydantic import BaseModel
from pydantic.errors import PydanticInvalidForJsonSchema
from pydantic.v1 import BaseModel as BaseModelV1
from pydantic.v1 import Field as Field_v1
from pydantic.v1 import create_model as create_model_v1
@@ -176,17 +177,32 @@ def _convert_pydantic_to_openai_function(
Raises:
TypeError: If the model is not a Pydantic model.
TypeError: If the model contains types that cannot be converted to JSON schema.
Returns:
The function description.
"""
if hasattr(model, "model_json_schema"):
schema = model.model_json_schema() # Pydantic 2
elif hasattr(model, "schema"):
schema = model.schema() # Pydantic 1
else:
msg = "Model must be a Pydantic model."
raise TypeError(msg)
try:
if hasattr(model, "model_json_schema"):
schema = model.model_json_schema() # Pydantic 2
elif hasattr(model, "schema"):
schema = model.schema() # Pydantic 1
else:
msg = "Model must be a Pydantic model."
raise TypeError(msg)
except PydanticInvalidForJsonSchema as e:
model_name = getattr(model, "__name__", str(model))
msg = (
f"Failed to generate JSON schema for '{model_name}': {e}\n\n"
"Tool argument schemas must be JSON-serializable. If your schema includes "
"custom Python classes, consider:\n"
" 1. Converting them to Pydantic models with JSON-compatible fields\n"
" 2. Using primitive types (str, int, float, bool, list, dict) instead\n"
" 3. Passing the data as serialized JSON strings\n\n"
"For more information, see: "
"https://python.langchain.com/docs/how_to/custom_tools/"
)
raise PydanticInvalidForJsonSchema(msg) from e
return _convert_json_schema_to_openai_function(
schema, name=name, description=description, rm_titles=rm_titles
)

View File

@@ -22,7 +22,8 @@ except ImportError:
from importlib.metadata import version
from packaging.version import parse
from pydantic import BaseModel, Field
from pydantic import BaseModel, ConfigDict, Field
from pydantic.errors import PydanticInvalidForJsonSchema
from langchain_core.messages import AIMessage, HumanMessage, ToolMessage
from langchain_core.runnables import Runnable, RunnableLambda
@@ -1171,6 +1172,38 @@ def test_convert_to_openai_function_strict_required() -> None:
assert actual == expected
def test_convert_to_openai_function_arbitrary_type_error() -> None:
"""Test that a helpful error is raised for non-JSON-serializable types.
When a Pydantic model contains a custom Python class that cannot be
serialized to JSON schema, we should raise a PydanticInvalidForJsonSchema
with a helpful error message explaining the issue and suggesting solutions.
See: https://github.com/langchain-ai/langchain/issues/34371
"""
# Define a custom Python class that isn't JSON-serializable
class CustomClass:
def __init__(self, name: str) -> None:
self.name = name
class SchemaWithArbitraryType(BaseModel):
"""Schema with arbitrary type."""
model_config = ConfigDict(arbitrary_types_allowed=True)
custom_obj: CustomClass = Field(..., description="A custom object")
name: str = Field(..., description="A name")
with pytest.raises(PydanticInvalidForJsonSchema) as exc_info:
convert_to_openai_function(SchemaWithArbitraryType)
error_message = str(exc_info.value)
# Check that the error message contains helpful information
assert "SchemaWithArbitraryType" in error_message
assert "JSON-serializable" in error_message
assert "Pydantic models" in error_message
def test_convert_to_openai_function_strict_defaults() -> None:
class MyModel(BaseModel):
"""Dummy schema."""