Skip to content

Invalid JSON in tool call arguments breaks session with Anthropic models #2061

@habema

Description

@habema

Problem

When a tool call contains invalid JSON arguments (e.g., missing closing brace), the session stores the invalid JSON string. This breaks the session with Anthropic models, as LiteLLM attempts to parse the arguments from JSON strings into JSONs (as per Anthropic API specs), and fails rightfully.

Root Cause

  1. Invalid JSON gets stored in session history in tool_call.arguments
  2. On reload, chatcmpl_converter.py:527 passes the invalid JSON string directly to litellm
  3. litellm converts OpenAI format (JSON string) → Anthropic format (dict) by calling json.loads()
  4. JSON parsing fails before tool invocation: "Expecting ',' delimiter: line 1 column 30"

Note:

Custom FunctionTool implementations can bypass the JSON validation that only happens in _on_invoke_tool_impl within function_tool, so this could cause unexpected behavior in those tools.

Repro Script:

@function_tool
def get_server_time(format: str = "%Y-%m-%d %H:%M:%S") -> str:
    """
    Returns the current server time, optionally in a specified format.
    """
    return datetime.now().strftime(format)


async def main():
    # Mimic session memory functionality.
    input_list = [
        {"content": "What is the current server time?", "role": "user"},
        {
            "arguments": '{"format":"%Y-%m-%d %H:%M:%S"',  # Invalid JSON on purpose
            "call_id": "call_9YhapDWwiCFcoGZilhyUo8ti",
            "name": "get_server_time",
            "type": "function_call",
            "id": "fc_0e0babe7f7b9bf95006910adb438588193a96b6a1d917c77e7",
            "status": "completed",
        },
        {
            "call_id": "call_9YhapDWwiCFcoGZilhyUo8ti",
            "output": "An error occurred while running the tool. Please try again. Error: Not implemented",
            "type": "function_call_output",
        },
        {
            "id": "msg_0e0babe7f7b9bf95006910adb5a4cc8193b5e3a1a171b76db1",
            "content": [
                {
                    "annotations": [],
                    "text": "I encountered an error trying to get the time now. Would you like me to try again?",
                    "type": "output_text",
                    "logprobs": [],
                }
            ],
            "role": "assistant",
            "status": "completed",
            "type": "message",
        },
    ]

    agent = Agent(
        name="Assistant",
        instructions="Reply very concisely.",
        model="litellm/anthropic/claude-haiku-4-5-20251001",
        tools=[get_server_time],
    )

    print("User: How about now?")
    result = await Runner.run(
        agent,
        input_list + [{"content": "How about now?", "role": "user"}],
    )

    print(result.final_output)

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions