Skip to content

fix: strip non-JSON-serializable defaults from @tool schema to prevent PydanticJsonSchemaWarning#1923

Open
frankgoldfish wants to merge 1 commit intostrands-agents:mainfrom
frankgoldfish:fix/tool-default-factory-warning
Open

fix: strip non-JSON-serializable defaults from @tool schema to prevent PydanticJsonSchemaWarning#1923
frankgoldfish wants to merge 1 commit intostrands-agents:mainfrom
frankgoldfish:fix/tool-default-factory-warning

Conversation

@frankgoldfish
Copy link

Summary

Fixes #1914.

When a @tool function parameter uses Field(default_factory=...), Pydantic includes the FieldInfo object as the default value in the generated JSON schema. Since FieldInfo is not JSON-serializable, Pydantic emits:

PydanticJsonSchemaWarning: Default value annotation=NoneType required=False default_factory=list description='items' is not JSON serializable; excluding default from JSON schema

Reproduction

from pydantic import Field
from strands import Agent, tool

@tool
def example(
    items: list[str] = Field(default_factory=list, description="items"),
) -> int:
    """Example tool."""
    return len(items)

Agent(tools=[example])  # emits PydanticJsonSchemaWarning

Root Cause

_clean_pydantic_schema() in decorator.py removes known Pydantic metadata keys but does not validate whether default values are JSON-serializable before they reach Pydantic's schema serializer.

Fix

After processing each property in _clean_pydantic_schema(), attempt json.dumps() on any default value. If it raises TypeError or ValueError, remove the default key.

The field remains optional and retains its type and description — only the non-serializable default sentinel is dropped, which is exactly what Pydantic was going to do anyway (with a warning).

Tests

Added test_tool_field_default_factory_no_pydantic_warning regression test that asserts no UserWarning is raised when accessing tool_spec for a tool with Field(default_factory=list).

…revent PydanticJsonSchemaWarning

When a @tool parameter uses Field(default_factory=...) or Field(default=...),
param.default is a FieldInfo object. Previously this was passed as:

    Field(default=<FieldInfo>, description=...)

Since FieldInfo is not JSON-serializable, Pydantic emitted:
  PydanticJsonSchemaWarning: Default value ... is not JSON serializable

Fix: in _extract_annotated_metadata(), detect when param_default is a FieldInfo
and forward its default_factory or default to the new Field() correctly.
Also inherit the FieldInfo's description when no higher-priority description exists.

Adds regression test covering default_factory, plain default, required, and
description forwarding cases.

Fixes strands-agents#1914
@frankgoldfish frankgoldfish force-pushed the fix/tool-default-factory-warning branch from d52f2e8 to 6999aaf Compare March 17, 2026 04:35
@github-actions github-actions bot added size/s and removed size/s labels Mar 17, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[BUG] @tool emits PydanticJsonSchemaWarning for Field(default_factory=list)

1 participant