cd /news/ai-agents/your-agent-ignored-a-failed-tool-cal… · home topics ai-agents article
[ARTICLE · art-100511] src=dev.to ↗ pub= topic=ai-agents verified=true sentiment=↑ positive

Your agent ignored a failed tool call. Here's how to catch that in CI.

Developer Ashwin Ugale released tracelint, an open-source linter that detects structural defects in AI agent execution traces without using an LLM. The tool reads telemetry from OpenInference, Arize Phoenix, Langfuse, or OpenAI formats and flags issues such as ignored tool errors, loops, and redundant calls, enabling deterministic CI gating. Ugale validated it against real traces, including a Phoenix export where it localized a genuine tool failure.

read4 min views1 publishedAug 17, 2026

You ship an AI agent. It calls tools, reads results, calls more tools, answers. Most of the time it works. Then a user reports something wrong, you open the trace, and you find it: the charge_card

tool returned a 402, and the agent just... kept going and told the customer their order shipped.

That's not a hallucination in the "made up a fact" sense. It's a structural defect in the run — an ignored tool error. And here's the thing about structural defects: you don't need another LLM to find them. They're decidable by looking at the trace.

That's the whole premise of tracelint: a linter for agent runs. It reads the execution trace — what the agent

Because for this class of bug, a judge is the wrong tool. Published trace-error benchmarks show LLM judges have low localization accuracy — they'll tell you "something seems off" without reliably pointing at which step. They're also non-deterministic, cost money per trace, and can't gate CI (would you fail a build on a coin-flip?).

Meanwhile, a whole category of agent bugs is structurally decidable:

None of these needs a model. They need the trace and a validator. That's what tracelint does.

pip install tracelint
tracelint demo --html demo.html

demo

runs a keyless validation suite — one planted instance of every defect, plus clean controls — and writes an HTML report. No API key, no model download.

To gate CI on a real trace:

tracelint check ./trace.json --tools ./tools.json    # exit 2 on a structural defect

Exit codes: 0

clean, 2

a structurally-provable defect, 3

an input error. Heuristic findings never fail CI on their own.

Here's the distribution insight. You're probably already instrumenting your agent — with OpenInference (the OpenTelemetry semantic convention for AI), feeding Arize Phoenix, Langfuse, or an OTel collector. tracelint reads that telemetry directly. You don't learn a new trace format; you point it at the spans you've got.

tracelint check spans.json --format openinference    # Phoenix, OTLP, TRAIL
tracelint check trace.json --format langfuse
tracelint check messages.json --format openai

Or straight from a running Phoenix instance, in Python:

import phoenix as px
from tracelint import lint_otel_trace

spans = px.Client().get_spans_dataframe().to_dict("records")
report = lint_otel_trace(spans)
print(report.exit_code)          # 0 or 2
for f in report.active_findings:
    print(f.rule, f.tier.value, f.summary)

I validated this against real OpenInference exports, not just hand-built fixtures — a real Phoenix trace, an OTel-SDK span export, the Phoenix dataframe shape. On one real Phoenix trace, tracelint deterministically localized a genuine tool failure:

[hard_event] R2a tool_error_event  (step 9)
  'add_spans_to_dataset' returned an error (GraphQL query 'exampleMutation' ... 'an unexpected error occurred')

No model in the loop. Just: this TOOL span has an ERROR status, at exactly this step, here's the message.

Rule Finding
R1 schema violation — args fail the tool's JSON Schema
R2 tool returned an error / an errored value reused by a later side-effecting call
R3 hallucinated argument — value not derivable from anything observed
R4 loop — N identical no-progress calls
R5 redundant call — identical call + identical result, no mutation between
R6 malformed arguments — the tool-call arguments aren't valid JSON
R7 unknown tool — a call to a tool absent from the declared toolset

Here's a stuck-loop run through the OpenInference adapter:

[candidate] R4 loop  (step 2,4,6)
  'search' called 3 times in a row with identical arguments and no change in result state (ok)
[candidate] R5 redundant_call  (step 2,6)
  'search' repeats an earlier identical call with no mutating call in between

1. Candidate, not verdict. Only structurally-provable things (a schema violation, malformed JSON) are hard defects that fail CI. Heuristic signals — loops, redundant calls, suspicious arguments — are shown as candidates with their evidence, for a human to review, never asserted as truth and never failing your build on their own. A retry loop and a stuck loop look similar structurally; tracelint shows you the evidence and lets you decide, instead of pretending it knows.

2. It tells you what it couldn't check. This is the one I care about most. If a trace is missing a field a rule needs — no tool schemas, no result payloads — that rule doesn't silently pass. It

suppressed (2) — not checked, not a clean pass:
  R1 schema_violation: no tool schema available for any called tool
  R7 unknown_tool: no tool registry supplied — cannot know which tools were declared

A clean report with hidden gaps is worse than no report — it's false confidence. tracelint refuses to give you that.

pip install tracelint
tracelint demo --html demo.html

It's open source (MIT), dependency-light (jsonschema

  • stdlib), Python 3.10–3.12, and the whole test suite is offline and deterministic.

If you're collecting agent traces and want deterministic checks on them, I'd genuinely like to know what breaks on your real exports — that's how the last three real-world shape fixes happened. Issues and traces welcome.

── more in #ai-agents 4 stories · sorted by recency
── more on @ashwin ugale 3 stories trending now
sponsored brought to you by zahid.host 4,200+ EU-deployed projects
reading about agents? ship yours in a single git push.

Run your AI side-project on zahid.host

EU-based hosting, git-push deploys, automatic HTTPS, no cold starts. Free tier with a custom domain — perfect for shipping the agent you just read about.

$git push zahid main
Live at https://your-agent.zahid.host
Get free account → Pricing
from €0/mo · no card required
LIVE [news/your-agent-ignored-a…] indexed:0 read:4min 2026-08-17 ·