n8n · Updated · 8 min read · Lukas Ceponis

AI agent not calling tools: read the n8n trace before you fix it

Agent trace harness (n8n workflow)Logs every tool call, the arguments the model sent, and the raw value that came back, so you can see exactly what the model was given.

An AI agent not calling tools is one of the two failures we now get asked about most, and its twin is worse: the tool runs, returns exactly the right data, and the model answers as though nothing came back. Both look like the model being stupid. Both are almost always a plumbing problem you can see in the trace within about ten minutes, and both have fixes that cost nothing except the willingness to stop editing the system prompt and go read what the model was handed.

This page has two real traces, the five causes that account for nearly everything we have seen, and a harness you can drop into any n8n agent workflow to record what happened on every turn.

AI agent not calling tools: what the trace has to show you

The n8n AI Agent node gives you a per-run log if you open the execution and click into the agent. What matters is the sequence of iterations, the arguments the model sent, and the raw value that came back. Guessing from the final answer alone will send you in circles for a day.

Case one, the tool ran and the model wrote around it

[Agent] iteration 1
  tool:        get_order_status
  arguments:   { "orderId": "SO-10442" }

[Tool]  get_order_status -> returned in 412ms
  {
    "orderId": "SO-10442",
    "status": "shipped",
    "carrier": "DHL",
    "tracking": "JJD014600010847264011",
    "eta": "2026-08-27"
  }

[Agent] iteration 2
  tool:        none
  output:      "I don't have access to order information in this chat.
                Please email support and they will look it up for you."

  usage: prompt 7,942  completion 31

The tool worked. The data was correct, on time, and sitting in the conversation. The model then refused a question it had the answer to, and the customer got sent to an inbox that takes two days to reply.

Two suspects here, and the prompt token count tells you which. At 7,942 prompt tokens on a small model with a chat memory window, the tool result may have been trimmed out of context before the second iteration ever ran; n8n's memory nodes keep a fixed number of past messages, and a verbose tool return plus a long conversation will push the useful part off the edge. The other suspect is a system prompt containing a line like "if you are unsure, tell the customer you do not have access to their data." That sentence is a permanent escape hatch, and models take it, especially when the returned JSON is not shaped the way the prompt described it.

Case two, the tool was never called

[Agent] iteration 1
  tool:        none
  output:      "Order SO-10442 is being processed and should ship
                within 3 to 5 business days."

  tools available: 4
  tool calls:      0
  usage: prompt 1,088  completion 22

Zero tool calls, four tools attached, and a confident invented answer. Now look at what the model was offered, because this is the definition n8n actually sends to the provider:

{
  "name": "HTTP_Request",
  "description": "",
  "parameters": {
    "type": "object",
    "properties": {
      "url":   { "type": "string" },
      "query": { "type": "string" }
    }
  }
}

A tool called HTTP_Request with an empty description is invisible in practice. The model never sees your node or your workflow. It gets the name, the description string, and the parameter schema, and it decides from those three fields alone whether the thing in front of it is relevant to what the user just asked. Given nothing to go on, it does what it was trained to do and answers from memory, which is the same mechanism behind a chatbot making things up.

Five causes worth checking, in this order

  1. The description is empty, generic, or written for you rather than for the model. "Gets data" and "Queries the database" tell it nothing. The description is the selection mechanism, so it needs the trigger condition in it: "Look up the live status, carrier, and ETA of a customer order by its order number. Use this whenever a customer asks where their order is." That single change fixes more agent bugs than anything else on this list.
  2. Parameter descriptions are missing, so the model cannot fill the arguments confidently and declines the call rather than guessing. Every property in the schema deserves one line, including the format you expect, because an agent that does not know whether orderId means SO-10442 or 10442 often just gives up.
  3. The tool result never reached the second turn. Chat memory windows and enormous tool returns both produce it. A tool that hands back 400 lines of JSON when the answer needs four fields will crowd itself out of the very context it was called into.
  4. The tool returned an empty array and the model believed it. This is the one people miss for weeks, so it gets its own section below.
  5. The system prompt contradicts tool use. Instructions to be concise, to answer from the conversation, to avoid speculation, or to escalate when unsure all compete with the instruction to call a tool, and the refusal branch usually wins because it is shorter and safer.

An error and an empty result arrive looking alike

These two returns mean completely different things to you and roughly the same thing to the model:

get_open_invoices -> []

get_open_invoices -> { "error": "ETIMEDOUT", "message": "connect ETIMEDOUT 10.0.0.4:5432" }

The first says the customer has no open invoices, which the model will report as fact, cheerfully and wrongly, if your query had a bad filter on it. The second is an outage, and if the node runs with "continue on fail" the error object gets passed into the conversation as if it were data, at which point the model tries to interpret a Postgres timeout as a business answer.

Make the difference visible at the tool boundary. Return something explicit when a lookup finds nothing, like { "found": false, "reason": "no invoices matched customer 88213" }, and let genuine errors throw so the agent can retry or hand off. A tool that always returns success teaches the model that success means nothing.

Log the whole exchange instead of reasoning about it

Everything above is guesswork until you can see the actual bytes. The harness attached to this page wraps your existing tools and writes one row per call: timestamp, tool name, the arguments the model sent, the raw return value before any formatting, the size of that return, and the model's next message. Import it, point your agent's tools through it, and run the conversation that failed.

The row that solves most cases is the raw return. Nine times out of ten the tool is returning something subtly different from what the builder assumed: a wrapped object where a bare array was expected, a stringified JSON blob the model has to parse in its head, a null in a field the prompt promised would hold a number, or an empty result caused by a filter that has been wrong since the day it was written.

Keep the log running after the fix. That is the cheapest form of the eval loop described in evals for business automations, and it turns "the agent is being weird again" into a row you can point at. We learned this expensively on somebody else's system: a lead-routing n8n flow doing about 200 runs a day, failing roughly once a day, with its only alert wired to a Slack channel that had been archived months before anyone noticed. Nobody was reading anything, so nobody knew.

Things you can fix today without hiring anybody

Most agent tool problems are twenty minutes of work once you know where to look, and I would rather you kept the money.

  • Write a real description on every tool, with the trigger phrase a user would say. Then read the tool list back as if you were the model and ask whether the right one is obvious.
  • Add a description to each parameter, including the expected format.
  • Trim the tool's return down to the fields the answer needs. Long returns crowd out everything else in the window.
  • Delete any line in the system prompt that gives the model permission to say it lacks access, unless that is genuinely the behaviour you want when a tool fails.
  • Check that your model supports function calling at all. Several smaller open models advertised as chat models do not, and n8n falls back to parsing tool calls out of plain text, which fails intermittently and looks exactly like the model ignoring you.
  • Run the failing conversation twice with the trace harness on before changing anything else.

If the agent starts behaving after those, close the tab.

Where paid help earns its keep

Bring us in when the agent is right most of the time and wrong unpredictably, when it has enough tools that selection itself has become the problem, when two tools overlap and it keeps picking the wrong one, or when it is answering real customers and nobody can say how often it has already invented something. Those are hard to fix by inspection because the failure only shows up across many runs, and the work is building the measurement before touching the prompt. It is the same call as a workflow that runs while nothing happens: the system reports success and the outcome is missing.

Our first step is a $500 written diagnostic delivered in 3 business days, credited in full against anything that follows. Small fixes are $750 to $1,500. A standard rescue lands between $1,500 and $4,000, a rebuild between $4,000 and $10,000, and all of it carries a 30-day bug warranty. The diagnostic is a document you keep, so you can take it to any other shop for a competing quote.

We run six systems in production, our own voice receptionist among them, and one of them is a document generator for a hydrogeology client that has produced 168 documents and holds 349 boreholes on file as of August 2026. That system calls tools on almost every run, and every one of those calls is logged, because the alternative is finding out from the client. If you want the same wiring on yours, start with the rescue service, and if the agent is one part of a larger build that keeps breaking, the piece on n8n workflows that keep failing is the wider version of this page.

What each band includes

Every band below is a fixed price agreed before any invoice. The diagnostic comes off the repair in full, so if you go ahead you have paid nothing extra for the reading.

BandPriceTime
Written diagnosticWe read the workflows, logs, and prompts. Written root-cause report and a fixed repair quote. Credited in full against the fix.$5003 business days
Small fixOne clear failure: a broken integration, a bad prompt, a missing retry. When the diagnostic shows a minor break, you pay the minor price.$750-$1,5002-5 days
Standard rescueWhere most rescues land. Several failure points or a fragile architecture: root-cause fixes, error handling, alerts, and a trail you can audit.$1,500-$4,0001-2 weeks
RebuildOnly when repairing costs more than starting over. The diagnostic says so in writing, with both numbers, before you decide.$4,000-$10,0002-4 weeks

Full detail on the rescue page, and every other number we charge is on the pricing page.

Other symptoms we have written up

Longer reading

Send us the execution log and we will tell you what broke

A thirty-minute call and a price at the end of it. If the fix is small enough to do yourself, we will say so on the call.