Skip to content

to_call_args: **kwargs keys that collide with named parameters silently override them or crash with TypeError #4669

Closed

Description

@mmjerge

Please read this first

Describe the bug

A function tool that takes **kwargs accepts schema-valid input that its Python signature cannot express: a key inside the kwargs dict that names one of the function's own parameters. FuncSchema.to_call_args does not check for this. What happens next depends on the parameter kind, and both outcomes are wrong.

1. Keyword-only parameter: the validated value is silently overwritten.

def g(*, opt: int = 1, **kw: Any) -> str: ...

# model sends {"opt": 5, "kw": {"opt": 9}}
# to_call_args -> args=[], kwargs={"opt": 9}
# the tool runs with opt=9, kw={}

The explicit opt=5 the model supplied — and Pydantic validated — is replaced, and the "opt" key disappears from kw. No error, no log. The tool executes with arguments that differ from the validated input.

2. Positional-or-keyword parameter: an unhandled TypeError escapes as an internal error.

def h(x: int, *rest: int, **kw: Any) -> str: ...

# model sends {"x": 1, "rest": [2, 3], "kw": {"x": 99}}
# to_call_args -> args=[1, 2, 3], kwargs={"x": 99}
# call is h(1, 2, 3, x=99)
# TypeError: h() got multiple values for argument 'x'

The invocation path (src/agents/tool.py:2632-2645) raises ModelBehaviorError for validation failures one line earlier, but the TypeError from the call itself is not converted. The run fails with an internal error instead of the model receiving actionable feedback.

Mechanism

FuncSchema.to_call_args (src/agents/function_schema.py:46-81) binds POSITIONAL_OR_KEYWORD parameters positionally and KEYWORD_ONLY parameters by name, then splats the VAR_KEYWORD dict with keyword_args.update(value or {}) — after the named parameters, with no intersection check. Dict update order produces the silent override; positional binding produces the TypeError.

Note the input is not nonsense the schema forbids: the generated Pydantic model has separate fields for opt and kw, and nothing constrains the keys inside kw. The schema says yes, then the call layer either lies or crashes.

Only non-strict tools are affected (strict_json_schema=False); strict mode rejects **kwargs tools at definition time. Positional-only parameters (def f(a, /, **kw)) are fine — kw={"a": ...} is expressible there and works today.

Debug information

  • Agents SDK version: main at e773b15; also v0.22.0
  • Python version: 3.10.16 (repo default via uv)
  • Operating system: macOS (darwin, arm64)
  • Model and model provider: n/a — reproduces with function_schema directly, no model or network involved
  • Does the issue reproduce with the latest Agents SDK release? Yes, and on main.
  • Does the issue occur consistently or intermittently? Consistently, deterministically.

Repro steps

Self-contained, no API key needed:

from typing import Any
from agents.function_schema import function_schema

def g(*, opt: int = 1, **kw: Any) -> str:
    return f"opt={opt} kw={kw}"

fs = function_schema(g, strict_json_schema=False)
data = fs.params_pydantic_model(**{"opt": 5, "kw": {"opt": 9}})
args, kwargs = fs.to_call_args(data)
print(g(*args, **kwargs))   # opt=9 kw={}   — the validated opt=5 is gone

def h(x: int, *rest: int, **kw: Any) -> str:
    return f"x={x} rest={rest} kw={kw}"

fs2 = function_schema(h, strict_json_schema=False)
data2 = fs2.params_pydantic_model(**{"x": 1, "rest": [2, 3], "kw": {"x": 99}})
args2, kwargs2 = fs2.to_call_args(data2)
h(*args2, **kwargs2)        # TypeError: h() got multiple values for argument 'x'

Expected behavior

The collision is not expressible as a Python call, so it should be rejected as model misbehavior: to_call_args should raise ModelBehaviorError naming the conflicting keys, consistent with how the invocation path already treats validation failures. That gives the model feedback it can correct instead of a silent wrong-argument call or an opaque internal error.

tests/test_function_schema.py has no coverage for kwargs-key collisions.

I have a fix with regression tests and will open a PR shortly.

Activity

  1. mikemikimike commented on Aug 27, 2026

    @mikemikimike

    Implemented in PR #4709.

    • Changed: Reject **kwargs keys that collide with named function parameters by raising ModelBehaviorError before tool invocation.
    • Tests: uv run --frozen pytest tests/test_function_schema.py -q (41 passed).
    • Validation: Ruff and git diff --check passed.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

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