My CrewAI agent fails without raising an error. Why?
Rius shows a CrewAI run that fails without raising an error as a trace whose root span finishes OK while a step inside it carries an error. That means the error was caught somewhere between the failing step and your entrypoint, so the run looks successful. Rius marks such a trace recovered, and the Swallowed Error alert fires on it when the errored step is not a tool call, so you hear about it next time. For the wider picture of watching agents in production, see Monitor AI agents in production.
How it works
- Status comes from the spans. A trace is
failedwhen at least one span has an OpenTelemetryERRORstatus. If the root span finished without an error of its own, the trace is badged recovered. The errors are still counted, only the verdict changes. - What CrewAI produces. Model calls arrive as
LLMgenerations namedChatCompletion, captured by theopenaiinstrumentation (thelitellmone when LiteLLM is installed). Yourobservewrapper around the crew’skickoff()is the rootAGENTspan, and tool bodies you wrap withobserveareTOOLspans. Crews and tasks produce no spans of their own, so a swallowed failure shows up as an erroredChatCompletionor tool span under a root that finished OK, not as a failed task. - Swallowed Error. This pre-defined alert fires when the root span finishes OK while at least one child step that is not a tool call ended with an error. A failed model call followed by a canned answer is the typical case. It fires once per run, and only on finished traces.
- Why tool errors are different. A failed tool call is returned to the model as the tool’s result, so the agent saw it and could react. Tool errors do not count toward Swallowed Error. Look at the
TOOLspan in the trace instead, and rely on Consistent Error Pattern when the same tool error repeats across runs.
Set it up
- Wrap the entrypoint and the tool bodies, so the trace has a root and your tools appear as spans. This is the setup from the CrewAI integration page, shortened:
import rius
from crewai import Agent, Crew, Task
from crewai.tools import tool
from rius import SpanKind
rius.init(api_key="ri_...", service_name="my-agent")
@tool("account_status")
@rius.observe(kind=SpanKind.TOOL)
def account_status(email: str) -> str:
"""Fetch a customer's account standing by email."""
return lookup(email)
@rius.observe(name="handle-ticket", kind=SpanKind.AGENT)
def handle_ticket(ticket: str) -> str:
...- Open Traces and filter the status to
failed. Rows badged recovered are the runs where child spans errored but the root finished clean. Those are your silent failures. Exploring traces covers the filters and saved searches. - Open one of those traces. The waterfall highlights failed spans along the path from the root to the error, and the detail panel for an error span leads with the exception and traceback. Press
]eto jump to the next failed span. - Check what failed. An errored
ChatCompletionunder a clean root means a model call failed and the code carried on. An erroredTOOLspan means the agent received the failure as a tool result. Use the Input / Output tab of the surrounding generations to see what the agent did next, if content capture is on. - To scan across runs, open the Spans tab, set All kinds to LLM or Tool, and filter by status.
- Catch it next time with Swallowed Error. It ships with Rius, and you can disable it but not delete it. To give one service its own bar or its own channel, an admin opens the alert’s details page and clicks Narrow this alert, then filters on the Root service. The same page lists the alert’s attached channels and its firing history.
What you get
- A clear reading of the symptom: a recovered trace means an error was swallowed, not that nothing went wrong.
- The failing step pinpointed, with its exception and traceback, instead of a clean-looking final answer.
- A Swallowed Error firing for each finished run where a non-tool step errored under a root that reported success.
- Consistent Error Pattern as a second net. It groups errored spans by service, step and error message, and by default fires at 3 errored spans across at least 2 distinct traces within 5 minutes.
- Retry chains collapsed into one row, such as a tool called three times with the last attempt succeeding, so a retry loop reads as one event.
The full list of integrations and their coverage is on the Integrations page.
When something else fits
- If no span carries an error and the answer is simply wrong, the trace shows a completed run. Read each generation’s Input / Output to see what the agent was given. Rius traces, prices and alerts on runs, and does not score answer quality.
- If the failure sits in crew or task logic, which produces no spans, wrap your per-task entrypoints with
observeso the trace shows which task each call belongs to. - If the agent repeats the same tool call with the same arguments instead of failing, Tool Loop is the better fit, and it counts only spans of kind TOOL.
Related
Last updated on