---
title: "Debugging Claude Code: loops, bad tool calls, hallucinated args"
description: "Fix the three common Claude Opus agent failures in Claude Code — infinite loops, wrong tool calls, and hallucinated arguments — with concrete harness fixes."
canonical: https://callsphere.ai/blog/debugging-claude-code-loops-bad-tool-calls-hallucinated-args
category: "Agentic AI"
tags: ["agentic ai", "claude", "claude code", "debugging", "tool use", "claude opus", "ai engineering"]
author: "CallSphere Team"
published: 2026-04-16T11:00:00.000Z
updated: 2026-06-06T21:47:43.420Z
---

# Debugging Claude Code: loops, bad tool calls, hallucinated args

> Fix the three common Claude Opus agent failures in Claude Code — infinite loops, wrong tool calls, and hallucinated arguments — with concrete harness fixes.

An agent that runs flawlessly in a demo and then wedges itself on the third real task is a familiar disappointment. With Claude Opus 4.8 driving Claude Code, the model is rarely the weak link — it reasons well, follows instructions closely, and recovers from most mistakes on its own. When an agentic run goes sideways, the cause is almost always in the harness around the model: an ambiguous tool description, a result format the model can't parse, or a loop the orchestration never bounded. This post walks the three failure modes you will actually hit — infinite loops, wrong tool calls, and hallucinated arguments — and gives you a debugging method that finds the real cause instead of blaming the model.

## Why agentic debugging is different

A single Claude API call either returns or errors, and you can read the whole transaction in one place. An agent is a feedback loop: the model emits a tool call, your harness runs it, the result re-enters the model's context, and the model decides what to do next. A bug at any point in that cycle propagates forward and compounds. By the time you notice the symptom — the run is stuck, or it deleted the wrong file — the originating mistake may be ten turns back.

The single most useful debugging asset is a full transcript: every message, every `tool_use` block with its exact `input`, every `tool_result` you fed back, and the `stop_reason` on each model response. Most teams log only the final answer and the model's prose, then find themselves guessing. Log the structured content blocks instead. A `tool_use` block carries the literal arguments the model chose, and the matching `tool_result` carries exactly what came back — the two together explain nearly every misbehavior.

## Failure mode one: the infinite loop

Loops have a recognizable signature: the model calls the same tool with near-identical arguments, gets a result it can't make progress on, and tries again. The classic trigger is a tool that fails silently — a search that returns an empty array with no explanation, or an edit tool that reports success but didn't actually change anything. The model has no signal that the action failed, so it retries, reasons about the same dead end, and retries again.

The fix is twofold. First, make every tool result *self-explanatory*: when a tool errors, set `is_error: true` and return a message the model can act on — "Error: file not found at path X. Use glob to locate it first" beats a bare empty string. The model reads that, changes approach, and moves on. Second, bound the loop in the harness. Track a turn counter and break with a clear message when it exceeds a ceiling; track repeated identical tool calls and short-circuit after two or three. You can also lean on the model's own self-moderation: Opus 4.8 supports **task budgets**, where you tell it how many tokens the whole loop has and it sees a running countdown, prioritizing and wrapping up as the budget shrinks instead of spinning.

```mermaid
flowchart TD
  A["Model emits tool_use"] --> B["Harness executes tool"]
  B --> C{"Tool succeeded?"}
  C -->|Yes| D["Return result with data"]
  C -->|No| E["Return is_error:true & how-to-recover"]
  D --> F{"Same call as last 2 turns?"}
  E --> F
  F -->|No| G["Continue loop"]
  F -->|Yes| H["Break: log transcript & escalate"]
  G --> A
```

## Failure mode two: the wrong tool call

When the model reaches for `bash` to do something a dedicated `edit` tool was built for, or searches the web for a fact already in context, the description set is usually the culprit. Claude chooses tools from their names and descriptions, so vague or overlapping descriptions produce vague or overlapping choices. The cure is to be **prescriptive about when to call each tool**, not just what it does. "Search the codebase for a symbol" is weaker than "Use this to find where a function or class is defined before editing it — prefer this over bash grep."

A subtler version on Opus 4.8: the model reaches for tools *less* often than earlier models, answering from context when you wanted it to search or delegate. If your agent should consult a search tool whenever current information matters, say so explicitly in both the system prompt and the tool's own description. Conversely, if it overtriggers a tool, the fix is almost always to dial back aggressive language like "CRITICAL: you MUST call this" — recent Opus models follow such instructions literally and will overuse the tool.

## Failure mode three: hallucinated arguments

This is the scariest-looking failure and often the easiest to engineer away. The model calls a real tool but invents an argument — a file path that doesn't exist, an ID it never saw, a parameter the schema didn't define. Two mechanisms eliminate most of these. Use `strict: true` on the tool definition so the model is constrained to your exact input schema with `additionalProperties: false`; the API then guarantees the arguments validate against your schema, so the model cannot emit a stray field. And always parse tool inputs with `json.loads()` or `JSON.parse()` rather than raw string matching — Opus may escape Unicode or forward slashes differently than you expect, and a brittle string comparison will mis-handle a perfectly valid call.

For arguments that refer to real-world entities — a file path, a record ID — the durable fix is to make the model *discover* the value rather than recall it. If the only way to get a valid path is to call `glob` first, the model can't hallucinate one. Design tool sequences so that identifiers flow out of earlier tool results and into later calls; a hallucinated ID then becomes structurally impossible rather than something you hope the model gets right.

## A repeatable debugging method

When a run misbehaves, work the transcript backward from the symptom. Find the first turn where the model's plan diverged from what you wanted, then ask which of three things was wrong: the information the model had (a tool result was empty, malformed, or misleading), the options it had (a missing or mis-described tool), or the loop control (no bound, no dedup). Reproduce in isolation by replaying the message history up to that turn against the API directly — because the Messages API is stateless, you can reconstruct any point in the run exactly and poke at it. Fix the harness, not the prompt, whenever the root cause is a tool that lied or a loop that never ended.

## Frequently asked questions

### Why does my agent loop even though the task is simple?

Almost always a tool that fails without saying so. The model retries because it has no signal the last attempt failed. Return `is_error: true` with an actionable message on every failure path, and add a harness-level dedup that breaks after two or three identical calls.

### How do I stop the model inventing arguments?

Set `strict: true` with a closed schema (`additionalProperties: false`) so arguments are validated against your definition, and design tools so identifiers come from prior tool results rather than the model's memory. A path the model had to discover via `glob` can't be hallucinated.

### Is a wrong tool call a model problem or a prompt problem?

Usually a description problem. Claude picks tools from their descriptions, so prescriptive "call this when…" wording fixes most mis-selections. On Opus 4.8, also check for overly aggressive language causing overtriggering, or missing guidance causing the model to skip a tool you wanted used.

### What's the fastest way to reproduce an agent bug?

Replay the logged message history up to the failing turn against the stateless Messages API. You get the exact context the model saw and can test fixes without re-running the whole agent from scratch.

## Bringing agentic AI to your phone lines

CallSphere takes these same debugging disciplines — self-explanatory tool results, bounded loops, validated arguments — and applies them to **voice and chat** agents that answer every call, use tools mid-conversation, and book work around the clock. See it live at [callsphere.ai](https://callsphere.ai).

---

*Source & attribution: This is an independent, original explainer inspired by Anthropic's coverage on the Claude blog. Claude, Claude Code, Claude Cowork, Claude Opus, and the Model Context Protocol are products and trademarks of Anthropic. CallSphere is not affiliated with or endorsed by Anthropic.*

---

Source: https://callsphere.ai/blog/debugging-claude-code-loops-bad-tool-calls-hallucinated-args
