Content

Invalid Tool Arguments in the OpenAI Agents SDK: Why the Model Sends the Wrong Parameters

What "Invalid JSON input for tool" means in the OpenAI Agents SDK, what strict mode guarantees and what it leaves out, why schema-valid arguments can still carry wrong values, and how to catch both kinds of error before a call runs.

AI AgentOct 7, 2026

Key takeaways

  • -In the OpenAI Agents SDK, "Invalid JSON input for tool" is a ModelBehaviorError raised when tool arguments fail to parse or fail validation against the tool's parameter model.
  • -By default, Python function tools send the error back to the model so it can try again, and failure_error_function controls what the model sees.
  • -Strict mode makes arguments match the schema on supported models, but OpenAI notes it can still miss on refusals and when generation stops at max_tokens.
  • -Strict mode does not check values. ParamBench found that only 2.1% of failed calls from seven frontier models violated the schema; the rest were well-formed with wrong values.
  • -Value errors need checks a basic schema leaves out: enums, constraints, cross-field rules, and lookups against real data.
  • -Swytchcode validates arguments against the provider's real API schema at execution time, so invalid inputs fail before the request is sent and provider errors come back in a form the agent can act on.

The OpenAI Agents SDK raises ModelBehaviorError with "Invalid JSON input for tool" when the model's tool arguments either fail to parse as JSON or fail validation against the tool's parameter model. Strict mode prevents most of these by constraining the model to the schema, but it only guarantees shape. A call can be valid JSON, match the schema exactly, and still carry the wrong values: the wrong ID, an amount in dollars where cents were expected, a date in the wrong year. Fixing invalid arguments means keeping strict mode on and handling the error well. Fixing wrong arguments means validating values against the real API before the call runs.

This article covers what the error means in the Python and TypeScript SDKs, what strict mode does and does not guarantee, why value errors are the larger problem, and how to catch both. Checked against the openai-agents-python and openai-agents-js repositories and OpenAI's documentation in October 2026.

What "Invalid JSON input for tool" means

Every function tool in the Agents SDK has a parameter schema. In Python it comes from the function's type hints through a Pydantic model. In TypeScript it comes from a Zod schema. When the model calls the tool, the SDK parses the arguments and validates them. Two kinds of failure raise the same error:

  • Parse failure. The arguments are not valid JSON. Since pull request #3166 in openai-agents-python, valid JSON that is not an object, such as an array, a string, or null, raises the same error so it follows the same retry path.
  • Validation failure. The JSON parses, but a field is missing, has the wrong type, or fails a constraint in the parameter model.

In the Python SDK, the default failure_error_function turns the error into a message the model sees and asks it to try again. Passing failure_error_function=None raises the error instead. In the TypeScript SDK, issue #799 noted that errorFunction received only a generic message, without the raw input or the underlying Zod error, which made targeted recovery hard.

Tool arguments can contain sensitive data, and the error message can include them. Setting OPENAI_AGENTS_DONT_LOG_TOOL_DATA keeps the payload out of logs and, since pull request #3485, out of the exception message as well.

What strict mode guarantees

With strict: true on a function definition, OpenAI constrains generation so arguments match the supplied schema on supported models, provided the schema stays within the supported subset of JSON Schema. Strict schemas list every property as required and set additionalProperties to false, which is why optional fields are written as a type that allows null. The Agents SDK builds strict schemas for function tools by default through its strict_mode setting.

OpenAI documents the limits. When it introduced Structured Outputs, it listed cases where output can still miss the schema, including a refusal and generation that stops at max_tokens. It also said plainly that Structured Outputs does not prevent mistakes within the values of the JSON object.

Why valid arguments are still wrong

ParamBench (arXiv 2608.03071, 2026) looked at failed tool calls from seven frontier models and found that only 2.1% violated the schema. The rest were well-formed calls with wrong values. Strict mode removes that 2.1%. The other failures pass every check the SDK runs.

ErrorExampleCaught by strict mode?
Malformed argumentsTruncated JSON, or an array where an object was expectedMostly. Truncation and refusals can still break it
Missing or extra fieldNo customer_id, or an invented fieldYes, on supported models with a strict schema
Wrong type"10" as a string where an integer is expectedYes
Wrong valueAn amount of 10 meaning dollars when the API expects centsNo
Wrong referenceA customer ID that exists but belongs to someone elseNo
Wrong operationA refund tool called when the user asked for a creditNo

How to reduce value errors

  1. Tighten the schema. Use enums, minimums, and other constraints wherever the API has them. Each one turns a value error into a validation error the SDK can catch.
  2. Describe units and formats. State units, ID formats, and examples in field descriptions. "Smallest currency unit, for example 1099 for $10.99" leaves far less room for error than "amount".
  3. Validate inside the tool. Check cross-field rules and look up referenced IDs before acting.
  4. Return actionable errors. Say which field failed and why. A generic "try again" invites the model to repeat the same call.
  5. Separate reads from writes. Let the agent look things up freely, and gate writes behind a preview or approval.
  6. Keep the tool list short. Fewer, clearly named tools reduce wrong-operation errors.
from typing import Annotated, Literal
from pydantic import Field
from agents import function_tool

@function_tool
def create_refund(
    payment_intent_id: Annotated[str, Field(description="Stripe PaymentIntent ID, starts with pi_")],
    amount: Annotated[int, Field(ge=1, description="Smallest currency unit, for example 1099 for $10.99")],
    reason: Literal["duplicate", "fraudulent", "requested_by_customer"],
) -> str:
    """Refund part or all of a payment."""
    if not payment_intent_id.startswith("pi_"):
        return "Invalid payment_intent_id: expected an ID starting with pi_."
    ...

The enum and the minimum are enforced by the schema. The ID prefix check runs inside the tool and returns an error that tells the model exactly what to fix.

Where Swytchcode fits

Swytchcode is an execution layer between agents and the APIs they call. A hand-written function tool carries whatever schema you wrote, and that schema drifts from the provider's API over time. Swytchcode holds the real operation schemas for the APIs in its catalog and for internal APIs added from an OpenAPI spec. Every call runs through one pipeline: resolve the tool, validate inputs, evaluate policies, resolve credentials, execute, and normalize the response. Credentials never pass through the model's context.

With the Agents SDK, the simplest connection is the Swytchcode MCP server over stdio. The agent then sees a small set of tools, such as discover, info, and exec, regardless of how many APIs the project uses, and reads each operation's real schema before calling it.

# Install, initialize, and enable the operations the agent needs
npm install -g swytchcode
swy init --mode=sandbox
swy discover "refund a payment" --json
swy get <project>
swy add <canonical_id>
import asyncio
from agents import Agent, Runner
from agents.mcp import MCPServerStdio

async def main():
    async with MCPServerStdio(
        params={"command": "swytchcode", "args": ["mcp", "serve"]},
    ) as swytchcode:
        agent = Agent(
            name="Billing agent",
            instructions=(
                "For any third-party API call, use swytchcode_info to read the "
                "schema, then swytchcode_exec. Preview writes with dry_run=true."
            ),
            mcp_servers=[swytchcode],
        )
        result = await Runner.run(agent, "Refund the duplicate charge on order 1042")
        print(result.final_output)

asyncio.run(main())

The Swytchcode docs also include an OpenAI Agents SDK quickstart.

What happens when the arguments are wrong:

  • Unknown or not-enabled operations are rejected. An invented canonical ID, or a real one that has not been added to the project, exits with code 2 and no request is sent.
  • Invalid inputs fail against the provider's schema. A missing required field, a wrong type, or a field the API does not define exits with code 1 before the provider sees the request. The check uses the API's real schema, so it stays correct when your own tool definitions would have drifted.
  • Provider errors come back structured. Each error includes the status code, an error category, and whether it is retryable. A 200 response with an error in the body counts as a failure.
  • Writes can be held. dry_run=true previews the request without sending it. For production, allow and deny rules are available from the Pro plan, and approval rules that route a call to Slack or Telegram are available on Business and Enterprise.

Where this does not help

Swytchcode checks inputs against the provider's schema, which catches missing, invented, and mistyped fields. It cannot tell whether a valid customer ID is the right customer, or whether the user meant a refund or a credit. Those are the value errors ParamBench describes, and they need careful tool design, confirmation of writes, and approvals for high-impact operations.

Frequently asked questions

What does ModelBehaviorError "Invalid JSON input for tool" mean?
The model's tool arguments either failed to parse as JSON or failed validation against the tool's parameter model. By default the Python SDK sends the error back to the model so it can try again.

Does strict mode guarantee correct tool arguments?
It guarantees that arguments match the schema on supported models, with exceptions such as refusals and truncation. It does not check that values are correct, and OpenAI said so when it introduced Structured Outputs.

Why does strict mode require every field?
Strict schemas list every property as required and set additionalProperties to false. Optional fields are expressed as types that allow null.

How do I stop the model from passing wrong values?
Tighten the schema with enums and constraints, describe units and formats, validate referenced IDs inside the tool, return specific errors, and gate writes behind a preview or approval.

Can I use Swytchcode with the OpenAI Agents SDK?
Yes. Connect the Swytchcode MCP server with MCPServerStdio using the command swytchcode and the args mcp serve, or follow the OpenAI Agents SDK quickstart in the Swytchcode docs.

Swytchcode resources

More content