OpenAI Agents SDKopenai-agents 0.22 · Python 3.10+
1
Curious builder0 XP earned · 300 to level 2
0 daysFinish a lesson to begin
Badge collection0 of 6 unlocked
25 small wins to finish your pathNext lesson

When a tool fails

Your tool talks to a database, and the database is down. The interesting question is what the agent does next.

python
@function_tool
def lookup_order(order_id: str) -> str:
    """Look up the status of an order by its id."""
    raise ValueError(f"{order_id} is not a real order")

Run it. The run does not crash. You still get three items and a sensible answer.

Example
result = await Runner.run(agent, "Where is order ZZZ?")

for item in result.new_items:
    print(type(item).__name__)
print()
print("answer:", result.final_output)

What the model was told

Example
for item in result.new_items:
    if item.type == "tool_call_output_item":
        print(item.output)

That sentence is the SDK's own wording, and it is all the model got. Your exception message is in there, which is why a tool that raises ValueError("ZZZ is not a real order") leads to a useful reply and one that raises ValueError("error") does not. The text you raise is a prompt.

What the SDK did

It caught the exception, turned it into a message, and handed that message back to the model as the tool's answer. The model then had a choice, exactly as it would with a successful answer, and it chose to tell the customer it could not find the order.

That is the default and it is usually what you want. An agent that dies because one lookup failed is worse than an agent that says it could not find something.

When you want it to stop instead

Some failures should end the run rather than be explained away. The decorator takes a handler for that.

python
@function_tool(failure_error_function=None)
def charge_card(amount: int) -> str:
    """Charge the customer's card."""
    ...

Passing None means the exception is raised instead of being handed to the model. Use it where a quiet retry would be dangerous, and leave the default everywhere else.

The rule of thumb
A model that is told "the tool failed" will often try again with different arguments, which is helpful for a typo and unhelpful for a card charge. That is the whole decision.
Try it yourself
  • Change the exception message and see it reach the model's answer.
  • Add a second reply that tries the tool again with a different id.
  • Print item.output on the tool output item and read what the model was told.

Slow is fine. Stopping is the only problem.