Skip to content

Python: tool results containing datetime/UUID/Decimal/Enum are reported to the model as a tool failure #2203

Description

@thejesh23

Summary

In the Python SDK, a tool handler that returns a Pydantic model (or a plain dict) with a datetime, date, UUID, Decimal, Enum or set field never reaches the model. Instead the model receives:

Invoking this tool produced an error. Detailed information is not available.

This happens on every call, and the tool author gets no indication of what went wrong.

Location

python/copilot/tools.py:352-360, in _normalize_result:

    # Everything else gets JSON-serialized (with Pydantic model support)
    def default(obj: Any) -> Any:
        if isinstance(obj, BaseModel):
            return obj.model_dump()
        raise TypeError(f"Object of type {type(obj).__name__} is not JSON serializable")

    try:
        json_str = json.dumps(result, default=default)
    except (TypeError, ValueError) as exc:
        raise TypeError(f"Failed to serialize tool result: {exc}") from exc

Root cause

BaseModel.model_dump() uses the default mode="python", which leaves datetime, date, time, UUID, Decimal, Enum and set as native Python objects. json.dumps then hands those objects back to the same default hook; they are not BaseModel instances, so the hook raises TypeError.

_normalize_result re-raises, and that raise happens inside wrapped_handler's try block (tools.py:268-280), which deliberately converts any exception into the redacted generic failure. So the advertised "Pydantic model support" only holds for models whose fields are all JSON primitives.

Reproduction

import datetime, decimal, uuid
from pydantic import BaseModel
from copilot.tools import _normalize_result

class Issue(BaseModel):
    id: uuid.UUID
    created_at: datetime.datetime
    price: decimal.Decimal

_normalize_result(Issue(
    id=uuid.uuid4(),
    created_at=datetime.datetime.now(),
    price=decimal.Decimal("1.5"),
))

Observed:

TypeError: Failed to serialize tool result: Object of type UUID is not JSON serializable

Through a real @define_tool handler the same input yields:

result_type: failure
text: Invoking this tool produced an error. Detailed information is not available.
error: Failed to serialize tool result: Object of type UUID is not JSON serializable

Impact

Returning a model with a timestamp or an id is ordinary tool design, so this is easy to hit and hard to diagnose — the redaction is intentional for security, but it also hides the fact that the failure is in the SDK's serializer rather than in the user's handler.

The TypeScript SDK is not affected: nodejs/src/session.ts:1074-1079 normalizes with JSON.stringify, and JS Date implements toJSON().

Suggested fix

Use Pydantic's JSON mode so each field is coerced to a JSON-native type before json.dumps sees it:

-            return obj.model_dump()
+            return obj.model_dump(mode="json")

Models whose fields are all JSON primitives serialize exactly as before. Happy to send a PR — I have one ready with a regression test.

For fuller parity with the TypeScript SDK you may also want fallbacks in default for dataclasses.asdict, datetime/date/time.isoformat(), UUID/Decimalstr, Enum.value and setlist, so a plain dict carrying those types works too. I left that out of the PR to keep the change focused.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions