Tuesday afternoon, your agent booked 40 calendar slots instead of one. No exception, no red text in the logs, no failed health check. Just a cheerful assistant doing the same thing over and over while your calendar turns into a Jackson Pollock painting.
That’s what AI agent debugging usually feels like. The code compiles, the tests pass, every API call returns 200, and the system still produces nonsense. You can’t set a breakpoint on “the model was vague here.” So you build a different set of habits.
Agent failures don’t look like normal failures
Conventional software breaks at a line. An agent breaks across a trajectory: a sequence of prompts, decisions, tool calls, and observations where any single step can send the run sideways. The model is non-deterministic, so the same input can take a different path on Tuesday than it did on Monday.
Three things make this harder than ordinary debugging:
- No stack trace. The failure shows up at step 9 but started at step 2, when the agent rewrote a date as “next Thursday-ish.”
- Silent degradation. A search tool returns an empty list, the agent reads that as “nothing exists,” and carries on confidently.
- Compounding error. Each step eats the previous step’s output. A small misread at the top becomes an absurd action at the bottom.
Once you accept that you’re debugging a trajectory and not a function, the rest of the workflow makes sense.
Trace everything before you change anything
The first instinct is to start editing prompts. Resist it. Without a record of what actually happened, you’re fixing the bug you imagine rather than the one you have.
Every run should produce a trace: the full prompt sent to the model, the raw response, every tool call with its arguments, every tool result, token counts, latency, and the step index. Store them somewhere queryable. One JSON file per run is fine at first. A table keyed on run_id is better once you’re past a hundred runs a day.
What a useful trace contains
- The exact system prompt, including a version hash, so you know which instructions were live
- Model name, temperature, and seed
- The input payload as received, not as reconstructed afterwards
- Each tool call: name, arguments, duration, and the raw response body
- Finish reason and token usage per step
If you’re building the loop yourself in Node, the practical guide to building AI agents with JavaScript that survive production covers where to put those hooks without turning your agent into a logging monster.
Reproduce the failure before you fix it
Non-determinism makes reproduction slippery, but you can get close. Capture the exact input, pin the model version, drop temperature to 0, and replay the trace against mocked tools. If the bug vanishes, it was probably sampling or a flaky dependency. If it survives, you have something to work with.
Some failures only appear in production. Long-running processes leak state between runs, credentials expire mid-trajectory, and a container that sleeps for eight hours wakes up holding a stale connection pool. The gap between a laptop run and a deployed one is worth understanding early, and this breakdown of what actually happens when your agent leaves your laptop saves a lot of confused staring at logs.
The five failure modes you’ll spend most of your time on
In practice, agent bugs cluster. Learn to recognise these and diagnosis gets much faster.
1. The loop
The agent calls the same tool with the same arguments forever, or alternates between two tools. Almost always caused by a tool result that doesn’t answer the question the agent asked, so it retries. Cap iterations hard, then log what the agent was looking for on each attempt.
2. Malformed tool arguments
Type mismatches, invented field names, dates in three formats inside one run. Validate arguments against a schema before execution and return a specific error to the model. A good error message is a prompt.
3. Silent tool failure
200 OK with an empty body. Or 200 OK with an error object buried inside. Check for business-level failure, not just transport failure, and surface it to the agent in plain language.
4. Context overflow
Long runs quietly lose their earliest instructions as the window fills. Watch token counts per step and prune deliberately instead of letting truncation happen to you.
5. Instruction decay
By step 12 the agent has forgotten the formatting rule from the system prompt. Re-assert critical constraints near the point of use, not only at the top.
If your agent started life as a template, a couple of these are baked into decisions you never made. That’s the trade-off covered in what AI agent templates actually save you, and where they bite.
Prompt bugs are usually context bugs
Nine times out of ten, when someone says the prompt is broken, the model never had the information it needed. The customer record was fetched but truncated at 2,000 characters. A tool returned a nested object and only the top level got stringified. The history was compressed thirty seconds before the critical detail arrived.
Print the exact string you’re sending, all of it. Read it as a stranger. Could you complete the task with only that? If not, neither can the model.
Isolate the agent from its tools
You can’t debug a reasoning problem while a network dependency is flapping. Mock every tool, freeze the responses into fixtures, and run the agent against those. Now the only variable left is the model itself.
Do the reverse too: test each tool using recorded agent arguments. Roughly half the time a “reasoning failure” turns out to be a parser that silently swallows a field. Building the loop from scratch helps, because you know where the seams are. The Python walkthrough on going from a 60-line loop to something you actually trust is a decent map of those seams.
Multi-agent failures need a different lens
With one agent you debug a trajectory. With five, you debug a conversation with no moderator. An agent hands off a half-finished task, the receiving agent assumes context that was never passed along, and the result comes back plausible and wrong. Trace at the level of the task rather than the agent: who owned it, what state travelled with it, and exactly where ownership changed hands.
Most of these turn out to be handoff failures. The patterns that keep handoffs clean are the same ones that stop orchestrating multiple agents from becoming a room full of people talking past each other.
Watch cost and latency, not just errors
A run that finishes in 47 steps when it should take 6 is a bug, even if the final output looks fine. Plot steps per run and tokens per run over time. A slow climb usually means a tool result got less useful, or the agent started hedging. Both show up as cost long before they show up as a customer complaint.
Leave a fence behind
Fix the bug, then turn the failing trace into a regression case. Keep a folder of golden runs with their inputs and expected key outcomes, and replay them against every prompt or model change. It won’t catch everything, because the model is a moving target, but it catches the embarrassing ones, like the afternoon you fix date parsing and accidentally break refunds.
Add an alert on loop detection, one on step count above a threshold, and one on tool error rate. Those three catch most of what pages you at 2am. You never fully eliminate the weirdness in an agentic system. You just get faster at finding it, and you build enough scaffolding that the weirdness shows up in a trace instead of in someone else’s calendar.

