Skip to content
GONATURELLE
Cross-vertical · Loop & runaway

Infinite tool loop

The agent repeats a tool call, or a short cycle of calls, without making progress until it hits a step limit or timeout. The user gets nothing useful, cost and latency spike, and downstream rate limits can affect other users.

Medium severityLoop & runawayCross-vertical
Scenario

A pharmacy benefits support agent answers coverage questions. Tools: search_formulary(drug_name, plan_id), get_plan(plan_id), and reply(text). The step budget is 50. The fictional member asks about a brand-name drug that this plan's formulary lists only under its generic name.

Input

Is Brandoxin 20 mg covered on my plan, and what tier is it?

How the trajectory goes wrong

The agent had no exit path for an empty result. Repeating near-identical queries cannot produce new information, and a useful response was available: say the brand was not found, ask for the generic name or check the generic, and offer a handoff. The loop is a reliability defect and a cost defect. Yao et al. (2024, tau-bench) found that even the best function-calling agent completed under 50% of retail tasks in a single trial and under 25% across eight trials (pass^8), and runaway retries are one of the ways multi-turn agents fail.

Root causes

  • No instruction or policy for what to do when a tool returns empty results.
  • Agents not tracking which argument combinations have already been tried.
  • Step budgets set high enough that loops look like slow successes in aggregate metrics.
  • Tools that return empty lists instead of informative messages (for example, 'did you mean' or 'search by generic name').
trace.jsonl5 stepsgate failed
  1. 1
    Step 1: get_plan returns the member's plan and formulary version.
  2. 2
    Step 2: search_formulary(drug_name='Brandoxin 20 mg') returns an empty list.
  3. 3
    Step 3: The agent tries 'Brandoxin', then 'brandoxin', then 'Brandoxin 20mg', each returning empty.
  4. 4
    Step 4: The agent cycles through the same four strings repeatedly, sometimes calling get_plan again between attempts.
  5. 5
    Step 5: At step 50 the run is terminated, and the member sees a generic error after 94 seconds. Token use for the case is 11 times the suite median.
AssertionError step 5: The agent had no exit path for an empty result. Repeating near-identical queries cannot produce new information, and a useful response was available: say the brand was not found, ask for the generic name or check the generic, and offer a handoff. The loop is a reliability defect and a cost defect. Yao et al. (2024, tau-bench) found that even the best function-calling agent completed under 50% of retail tasks in a single trial and under 25% across eight trials (pass^8), and runaway retries are one of the ways multi-turn agents fail.

How GONATURELLE detects it

Cycle detection

no_cycles flags any repeated tool call with equivalent arguments beyond a threshold, and any repeating sequence of calls, using normalized arguments so case and whitespace changes count as repeats.

Step and cost budgets

max_steps and per-case token budgets are asserted per case class. GONATURELLE also tracks cost and latency drift across pull requests so a loop introduced by a prompt change shows up as a cost regression in the PR comment.

Empty-result cases

The pack includes cases engineered to return empty, partial and error results, with labelled expected behavior: clarify, fall back, or hand off.

test_runaway.py
from gonaturelle import EvalSuite, assertions as A

suite = EvalSuite.load('cross-vertical/empty-result-handling-v1')
results = suite.evaluate(agent=benefits_agent, max_concurrency=10, step_limit=50)
results.assert_tool_schema_valid()

results.assert_all([
    A.no_cycles(max_repeats=2, normalize_args=True),
    A.max_steps(12),
    A.calls_any(['ask_clarifying_question', 'escalate_to_human', 'search_formulary_generic'], when='case.empty_result'),
])

results.assert_metric('tokens_per_case', max_ratio_to_baseline=1.3)
results.assert_metric('p95_latency_s', max_ratio_to_baseline=1.25)

Mitigations

  1. 01Give the agent explicit empty-result policies and test them case by case.
  2. 02Have tools return actionable messages on empty results, such as suggested alternate identifiers.
  3. 03Track tried arguments in agent state and block exact or normalized repeats.
  4. 04Lower step budgets per task class and treat budget exhaustion as a failure, not a timeout.

Questions about this failure

Isn't a step limit enough protection?

A step limit stops the damage at the cost of a failed interaction and wasted spend. Loop detection in CI finds the missing exit path so the limit is rarely reached.

Is Brandoxin a real drug?

No. It is an invented brand name used in the test case so the formulary lookup fails predictably.

Explore the 2026 Vertical AI Reliability Index: failure rates across 12 regulated domainsSchema adherence, trajectory completion, domain factuality and adversarial robustness for 48 models. Free to cite.View the index

Stop testing regulated agents on generic prompts.

Run your agent against 100 industry-standard clinical or financial edge cases in 5 minutes. 14-day free production trial, no card.