CrewAICrewAI 1.15 · Python 3.10 to 3.13
0%
1
Curious builder0 XP earned · 300 to level 2
0 daysFinish a lesson to begin
Badge collection0 of 6 unlocked
32 small wins to finish your pathNext lesson

Tools that break mid-run

A tool that raises does not stop the crew. The error text goes to the model, the run finishes, and the failure is recorded on the result where your code can check it.

Lesson 9's tool always answered. A real order system goes down. Here the tool raises instead.

Examplecrew.py, from lesson 9
from crewai import Agent, Crew, Task
from shop_llm import ShopLLM
from tools import lookup_order

clerk = Agent(
    role="Order clerk",
    goal="Find the status of customers' orders",
    backstory="You can look up any order in the shop's system.",
    llm=ShopLLM(model="shop"),
    tools=[lookup_order],
)
task = Task(description="Answer the customer: {question}",
            expected_output="The order's status in one sentence.", agent=clerk)
crew = Crew(agents=[clerk], tasks=[task])
Exampletools.py, while the database is down
from crewai.tools import tool


@tool
def lookup_order(order_id: str) -> str:
    """Look up an order's shipping status by its id, such as A17."""
    raise ConnectionError("the order database is not answering")
Example
result = crew.kickoff(inputs={"question": "Where is my order A17?"})
print(result.raw)

The crew finished, and its answer is the error. CrewAI caught the exception and sent Error executing tool: and the message to the model as the tool's result. Your model repeated it. A hosted model would write something politer, and the run would look like a success.

Checking the result

Example
result = crew.kickoff(inputs={"question": "Where is my order A17?"})

print(result.has_tool_failures)
for record in result.tool_failures:
    print(record.tool_name, "|", record.failure.message)

CrewAI records the failure even though the run completed. The documentation's advice is to check has_tool_failures before treating raw as complete. A desk could send the ticket to a person instead of mailing the customer.

Stopping the run instead

Example
task.tool_failure_policy = "raise"
try:
    crew.kickoff(inputs={"question": "Where is my order A17?"})
except Exception as error:
    print(type(error).__name__)
    print(error)

tool_failure_policy has three values: warn, the default you saw, records the failure and continues; raise stops the run with ToolExecutionFailedError; ignore records nothing. The two warning lines come from CrewAI's event bus as the failed run unwinds. The policy can be set on a tool, a task, an agent or the crew, and the most specific setting wins.

Try it yourself
  • Set the policy to "ignore" and print has_tool_failures.
  • Set the policy on the agent instead of the task.
  • Make the tool return a normal string for C40 and raise only for other ids.

Every expert started right here.