Debugging Agent Systems: Traces, Replays, Root Causes
Agent failures raise no errors. The logging, tracing, and replay toolkit that makes them debuggable.
Evaluating Agents: Golden Sets, Judges, and Shadow Mode gave you the tools to measure whether your agent works. Now we face the harder problem: when the evaluation says it's broken, how do you find out why?
Agent failures are invisible. No stack trace, no exception, no segfault. A Mailmind reply that fabricates a refund amount looks just like a correct one. Debugging means reconstructing what the agent saw and did at each step. This article covers the structured logging, tracing, replay, and root cause analysis that turn agent failures into fixable bugs.
Rerunning an agent with the same input rarely reproduces the same failure. Sampling, tool call order, and retrieval noise mean that the bug you saw yesterday may be gone today. You can't fix what you can't see twice. That's why replay debugging, not fresh reruns, is the cornerstone of agent debugging.
Why do agent failures produce no errors?
Traditional code fails deterministically. A null pointer dereference crashes the same way every time. An agent fails by producing a wrong output that looks completely valid. The system never raises an error because, from its perspective, everything worked. The LLM (large language model) returned a coherent response. Tools executed without exceptions. The pipeline completed.
The analogy that sticks: debugging code is fixing a broken pipe. You see the leak and trace it back. Debugging an agent is figuring out why a person made a bad decision. You need to know what they saw and what they did at each step. Without that record, you're guessing.
Mailmind shows this clearly. A user asks "Did my refund for order #4521 go through?" The agent checks the order database, sees a refund status of "pending," and replies "Your refund of $47.23 has been processed." The answer is confident, fluent, and completely wrong. No error was thrown. The refund tool returned valid data. The agent simply invented the amount and the completion. You only discover the bug when the user complains.
This failure mode is why observability in agent systems must be built differently. You can't rely on error rates. You need a record of every model call, every tool call, every retrieval result, and every guardrail trigger. That record becomes your debugger.
What are the four categories of agent failures?
Most agent failures fall into one of four buckets. Knowing which bucket you're in tells you where to look first.
Reasoning failures: the agent had the right information but drew the wrong conclusion. In Mailmind, the agent correctly retrieved a meeting invite for 3 PM but replied "I'll see you at 2 PM." The model's written reasoning suggests it misread the time. Treat that reasoning as a clue, not a confession. Models do not always write down what actually drove the answer: in one study (Turpin et al. 2023, Language Models Don't Always Say What They Think), chain-of-thought explanations could systematically misrepresent the true reason for a model's prediction. Many APIs also return only a summary of the reasoning, or none: Anthropic's documentation on thinking, for example, says the text in a thinking block is never the raw chain of thought but a summary, and that recent models omit it unless you ask. Confirm a reasoning failure by replaying the run with one input changed. Fix: clearer prompts, constraints, or few-shot examples that anchor the correct behavior.
Tool failures: the agent called a tool but got bad data, no data, or a malformed response. Mailmind's calendar tool might return an empty JSON (JavaScript Object Notation) result because an auth token expired, and the agent proceeds as if no meetings exist. Diagnosis: log every tool call's input and output. Fix: add retries, validation, and explicit error handling so the agent knows when a tool has failed.
Memory failures: the wrong information was retrieved, or critical information was dropped. Mailmind's retrieval step might pull an old refund policy instead of the current one, or the runtime's trimming might drop the order history before the call. Diagnosis: log what was retrieved and what was in context. Fix: adjust embedding models, retrieval parameters, chunking, or context management.
Orchestration failures: the wrong agent was called, state was lost between steps, or the pipeline hung waiting for a reply. In a multi-agent Mailmind setup, the manager agent might route a receipt-filing task to the meeting scheduler. Diagnosis: trace the full flow of agent handoffs. Fix: tighten routing criteria, validate state passing, and add heartbeats and timeouts.
These categories aren't mutually exclusive. A single bad output often cascades through multiple layers. The debugging process isolates the first domino.
How do you trace an agent run end-to-end?
A trace is a timestamped, structured record of every step in an agent run. It captures model calls, actions, observations, tool inputs and outputs, retrieval results, confidence scores, handoffs, and guardrail triggers. This is not a log file of print statements. It's a machine-readable, queryable timeline.
For Mailmind, a trace of a single email handling might look like this:
Every node in that diagram carries a payload: the exact prompt fragment, the tool response JSON, the retrieved document chunk, the guard score. When a user reports a wrong refund amount, you pull the trace and see that at step E the order status was "pending," but the draft at step J says the refund was processed. The tool gave the right answer. The step from observation to reply went wrong, so the bug is in reasoning, not the tool.
Tracing is far easier to build in from day one than to retrofit, so make every component emit spans (one span per step, with its timing and payload) from the start. You do not have to invent the format. OpenTelemetry, the open standard for traces, has Semantic Conventions for GenAI agent and framework spans that define spans for model calls, agent runs (invoke_agent) and tool calls (execute_tool). As of October 2026 they are still marked Development, so expect changes. Add your own attributes for things like retrieval scores.
You do not have to build the viewer either. Tracing platforms such as LangSmith, Langfuse, Arize Phoenix and Datadog's Agent Observability (formerly LLM Observability) capture traces through SDK integrations or OpenTelemetry, show each run as a timeline, and let you turn failing runs into evaluation cases.
How does replay debugging work for nondeterministic systems?
Fresh reruns cannot reproduce a specific failure, though they are useful for measuring how often it happens: run the same input 20 times and count the failures. To reproduce one failure, the sampling, the order of async tool calls, and the retrieval noise all have to match. Replay debugging makes that happen by storing the complete input state of a run and feeding it back.
A replay record includes the exact text the model generated at each step, the tool responses (cached, not re-executed), and the retrieval results. You cannot regenerate the model's text reliably: providers do not guarantee identical output even with temperature 0 or a seed. Anthropic's glossary says that even with temperature set to 0, identical inputs may produce different outputs. So you record the text the model generated at each step and feed it back in place of the model's answer. When you replay, the agent follows the same path because every decision point gets the same inputs.
Mailmind's replay system captures the full state: the user email, the retrieved order data, the refund policy chunk, the generated draft. You can step through the run in a debugger, inspect the prompt at each step, and see exactly where the agent went wrong. This is the equivalent of a core dump for agent systems.
Step-through mode takes this further in development. You pause after each step and inspect the state. You can even edit the prompt or a tool response mid-run, and let the model generate live from that point, to test hypotheses. This is how you answer "what would have happened if the retrieval returned the correct policy?"
What does a systematic debugging process look like?
When a Mailmind user reports a wrong reply, you follow a repeatable process.
Reproduce. Pull the trace for that specific run. If you have replay, execute the replay and confirm the bug appears. Without replay, you're stuck trying to reconstruct the state from logs.
Isolate the component. Use the trace to identify which step first produced wrong information. Was it a retrieval that returned stale data? A tool that timed out silently? A reasoning step that invented a fact?
Inspect the prompt at that step. Look at the exact prompt assembled there. Often the bug is visible right away: garbage tool output injected into the prompt, missing instructions, or a missing few-shot example.
Identify the root cause. Classify it using the four categories above (reasoning, tool, memory, orchestration). Also check for plain infrastructure causes such as timeouts and expired auth, which often show up as tool failures. The category tells you where to fix.
Fix and verify. Apply the fix and replay the run with the fixed component generating live (a pure replay would only repeat the recorded mistake). The bug should disappear. Then run the full evaluation suite from Evaluating Agents: Golden Sets, Judges, and Shadow Mode to make sure you haven't regressed elsewhere.
Post-mortem and golden set. Write a brief post-mortem. Add the exact input and expected output to your golden set so the same failure cannot pass silently again.
This turns agent debugging into a repeatable process.
What failure signatures should you recognize immediately?
Some failure patterns are so common they have signatures. Learn to spot them in the trace without deep inspection.
Hallucination spiral: the output is confident, fluent, and completely unsupported by any citation. In the trace, you'll see no tool calls or retrieval steps that back the claim. Fix: add a factuality guard that requires citations, and log when the guard fires.
Tool call loop: the agent calls the same tool with slightly different parameters, over and over, never making progress. Mailmind might call the calendar availability check 15 times with dates one day apart. The trace shows a repeating pattern. Fix: add a maximum tool call count or a semantic deduplication check.
Context contamination: a reply about order #4521 suddenly references details from a different thread. The trace shows that the agent's context included both threads. Fix: isolate context per conversation, clear state between runs, and scan outputs for cross-thread leakage.
Silent truncation: the agent consistently misses information buried deep in long threads. The trace shows that your runtime's trimming dropped the relevant messages before the call (most APIs reject an over-long request rather than cutting it, so the cut happened in your code). Fix: add coverage checks that verify all critical sections are present, and use the strategies from Context Window Management for Big Jobs.
Hang or deadlock: the pipeline simply stops. The manager waits for a worker that has crashed, or two agents each wait for the other (a true deadlock, as Multi-Agent Orchestration: Managers, Workers, and Pipelines explains). Fix: add heartbeats and timeouts on all inter-agent communication.
Confidence inflation: the agent assigns high confidence scores to wrong outputs. The trace shows a confidence of 0.97 on an invented refund amount. Fix: calibrate confidence with examples, and add an independent scorer that evaluates the output separately.
Recognizing these signatures in the trace lets you jump straight to the fix.
Quick Reference: Failure Categories at a Glance
| Failure Category | Diagnosis | Fix |
|---|---|---|
| Reasoning failure | Compare the observations with the output; read the written reasoning as a clue and confirm by replay | Clearer prompts, constraints, examples |
| Tool failure | Log tool call input and output | Retries, validation, error handling |
| Memory failure | Log what was retrieved and what was in context | Re-embed, adjust retrieval parameters, chunking |
| Orchestration failure | Trace the full flow of handoffs | Validate state passing, tighten routing, heartbeats and timeouts |
Frequently Asked Questions
Q: Why can't I just rerun the agent to reproduce a bug? Sampling, tool call ordering, and retrieval noise mean the same input rarely produces the same output, and providers do not promise identical output even at temperature 0. The bug you saw yesterday may not appear today. Replay debugging stores the exact state so you can reproduce the failure. Reruns still help in one way: they tell you how often a failure happens.
Q: How do I log agent runs without blowing up storage costs? Log structured events, not full text dumps. Store what you need for replay: tool responses, retrieval results, and the model's output at each step. You don't need to store every token probability. Do not keep full traces only for failures, because at write time you do not know which runs failed: the refund bug above surfaced only when the user complained. Keep full traces for every run for a retention window (for example 14 days). Keep them permanently for high-stakes actions and for any run with a guardrail trigger, low confidence or a user complaint. Sample the rest for long-term storage.
Q: What's the difference between a trace and a log? A log is a stream of discrete events. A trace is a tree of spans that shows causal relationships: which step led to which. In agent debugging, you need the trace to see which model call led to which action and what observation came back. Logs alone can't reconstruct the decision tree.
Q: How do I debug a tool call loop that never errors? Look at the trace for the repeating pattern. Add a maximum call count or a semantic deduplication check that compares the current tool call to the last few calls. If the parameters are nearly identical, break the loop and return a clear signal to the agent.
Q: When should I use replay vs. step-through debugging? Use replay to reproduce a production failure exactly. Use step-through in development to pause after each step, inspect state, and test hypotheses by editing prompts or tool responses mid-run. Replay is for diagnosis; step-through is for experimentation.
Test yourself
You added a fourth worker, attachment analysis, to Mailmind's three-worker pipeline (order lookup, calendar, refund policy). Now the pipeline is 3x slower, and some email threads show no attachment results at all. No errors appear in the logs. What do you check?
Answer: You have two separate bugs. For the speed, open a trace and read the span timings. One more worker of similar length, run after the others instead of beside them, would make the run at most about twice as slow. So 3x means either the change made all four workers run one after another (fix the fan-out), or the new worker is slow on its own, with large attachments or external calls (check its span duration). The missing results are a routing or execution problem. Trace whether the manager routes threads with attachments to the new worker at all; the routing criteria might be too narrow. If the worker does receive the task, inspect its trace: it may be running but returning nothing because its prompt is too strict about what counts as a valid attachment. Finally, add a coverage check: every thread with an attachment must produce a record from the attachment worker, and a missing record raises an alert.
Next: Entity Resolution: One Thing, Many Names. It covers how an agent's memory recognizes that two names, addresses or accounts belong to the same person.
If you want this kind of breakdown every week, how real systems actually work under the hood, subscribe to Internals Decoded at internalsdecoded.com.
Sources
- ReAct: Synergizing Reasoning and Acting in Language Models, the paper behind the thought, action and observation loop whose steps a trace records.
- Language Models Don't Always Say What They Think
- platform.claude.com · Thinking
- Semantic Conventions for GenAI agent and framework spans
- docs.langchain.com · Home
- langfuse.com · Docs
- Arize Phoenix
- Datadog's Agent Observability
- platform.claude.com · Glossary