Repository navigation
Description
Please read this first
- Have you read the docs? Yes.
- Have you searched for related issues? Yes. fix: chat completions extra_args collision with omitted kwargs #3192 and fix(models): allow extra_args when chat completions kwarg is omitted #3200 cover
extra_argscollisions on the model-call path; nothing covers**kwargscollisions inside tool invocation.
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:
mainat 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_schemadirectly, 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
mikemikimike commentedon Aug 27, 2026
Implemented in PR #4709.
**kwargskeys that collide with named function parameters by raisingModelBehaviorErrorbefore tool invocation.uv run --frozen pytest tests/test_function_schema.py -q(41 passed).git diff --checkpassed.