You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Tool node type used: n8n-nodes-base.postgresTool (a regular node used as a tool via the "usable as tool" mechanism, not a purpose-built LangChain tool node)
Symptom
With a real production workflow (Twilio WhatsApp assistant), the AI Agent never calls any of its connected tools when a large static systemMessage (~50KB, built from a business prompt template) is used. The model always finishes with stop_reason: "end_turn" (via the AI Agent's own text output — it never even attempts a tool call), narrating an intention to check something ("let me check...") and then answering from its own embedded knowledge/hallucination instead of calling any tool. No error is raised anywhere — the execution completes successfully.
This was fully reproducible and is not intermittent — confirmed across all real executions retained in the database (11 days of history).
What this is NOT (ruled out with direct evidence)
Not the Anthropic API's payload validation / size limit. The exact same request body (large system, tools, messages) that fails through the n8n AI Agent was sent directly to https://api.anthropic.com/v1/messages (bypassing n8n's LangChain node and our internal caching proxy entirely, using n8n's httpRequest node with predefinedCredentialType) and it worked correctly (stop_reason: "tool_use"), both as a plain string system and as the array-with-cache_control format our proxy produces.
Not our internal caching proxy (source read in full — it does a JSON parse/mutate-system-only/stringify pass, no field is dropped; confirmed via direct byte-for-byte reproduction of its output sent straight to Anthropic).
Not the number of connected tools. Full elimination matrix below.
Not prompt-caching related (cache_control present or absent makes no difference at the API level, confirmed by direct testing both ways).
Elimination matrix (prompt size × number of tools)
All runs below use the same isolated test workflow, same AI Agent/model config, same credential, only systemMessage length and the set of connected tools varied.
systemMessage
# tools connected
Result
short (~100 bytes)
1
tool called
long (~50KB)
1
tool NOT called
long (~50KB)
4
tool NOT called
long (~50KB)
7 (matches production)
tool NOT called
short (~100 bytes)
7 (matches production)
tool called
Number of tools has zero measurable effect — only systemMessage length correlates with the failure.
Two distinct, overlapping causes found under "large prompt"
Cause #1 — tool node missing toolDescription (closed, root cause understood)
A postgresTool node with no descriptionType/toolDescription set at all (relying purely on default/auto behavior) fails to be included/used when systemMessage is large. The same node, unmodified, with a short systemMessage, works fine — so an empty description alone is not sufficient to reproduce it; it only manifests combined with a large prompt.
systemMessage
tool has toolDescription?
Result
short
no
tool called
short
yes
tool called
long
no
tool NOT called
long
yes
tool called
Direct-to-Anthropic confirmation: a tool schema with no description field at all, combined with the same ~50KB system prompt and cache_control, sent straight to the Anthropic API, still resulted in stop_reason: "tool_use" — the raw API tolerates a description-less tool fine, at any prompt size. So this is n8n-side behavior, not an Anthropic API constraint.
Cause #2 — tool WITH a proper, well-formed toolDescription STILL fails with a large prompt (root cause NOT understood)
Using a different tool (Consultar Preço do Serviço in our production workflow) that has a clear, well-formed toolDescription string, connected alone, with the same ~50KB systemMessage: the tool is still never called. This rules out Cause #1 as the sole explanation — there is a second, distinct failure mode triggered by prompt size alone, independent of whether the tool has a description.
We have not identified the mechanism for Cause #2. It reproduces reliably in our environment but we stopped investigating further at this point to avoid speculation without evidence.
Related but separate bug already fixed on our side (do not conflate)
Independently, we also found and fixed the known $fromAI() issue where omitting the explicit type argument ($fromAI(key, description) instead of $fromAI(key, description, "string")) can produce a malformed JSON Schema and cause a tool to be silently skipped — this matches #18588 and community reports of "type": "None" schemas. This is a real, separate, already-understood bug that we fixed by adding the explicit type to all our $fromAI() calls. It is not the cause of the symptom described in this issue — both Cause #1 and Cause #2 above were reproduced with the type argument already correctly present.
How to reproduce (minimal workflows attached)
Two exportable minimal workflow JSON files are attached in a follow-up comment on this issue (reproduces with a placeholder Postgres/Anthropic credential swapped in):
repro_causa1_tool_sem_descricao.json — single postgresTool with notoolDescription, large filler systemMessage. Fails to call the tool. Swap AI Agent.parameters.options.systemMessage to reference {{ $json.systemPromptSmall }} instead of {{ $json.systemPrompt }} to see it work.
Both need an Anthropic credential and a Postgres credential (any reachable Postgres instance works — the query itself is trivial and only exists to give the tool a $fromAI() parameter). Replace the placeholder credential IDs before running.
To trigger: use "Execute workflow" from the n8n editor (Manual Trigger), send message "My name is Fernanda". Two complementary checks confirm whether the tool was genuinely invoked, and both were used throughout this investigation:
Per-node signal: in the execution data, check whether the tool node's name appears as a key in resultData.runData, with a metadata.subRun entry and real extracted arguments under data.ai_tool — this confirms the model's tool-use loop actually reached that specific node. This is what the elimination matrix above is based on.
Full-payload signal: n8n's execution record captures the exact request body sent to the model verbatim (under the chat model node's inputOverride). A full-text search for the literal substring "tools" across the complete execution JSON shows whether a tools array was present anywhere in that call. This is the method behind this report's central finding — 0 occurrences in every failing execution we inspected, versus present (and accepted) when the same payload was sent directly to api.anthropic.com bypassing n8n. Note toolDescription (the tool node's static config parameter) shows up regardless — that's workflow metadata, not the runtime request, and should not be confused with an actual tools array in the call.
Both checks agreed in every case we tested. The one thing that is not a valid signal is inferring tool use indirectly from a business-level side effect (e.g., "a database row was created, so the tool must have run") — in our production workflow a separate deterministic fallback (unrelated to the AI Agent's own tool-calling) can produce the same side effect from the model's plain text output, independent of whether any tool was actually invoked.
Summary
Confirmed: not an Anthropic API limitation (same payload works when sent directly).
Confirmed: not proxy/cache-related, not tool-count related, not the $fromAI() type bug (fixed separately).
Confirmed root cause for one specific pattern (Cause No json data from any APIs #1: missing toolDescription + large prompt).
Confirmed real but unexplained second pattern (Cause [feature request] Fliter events/actions in realtime #2: even a well-described tool fails under the same large-prompt condition) — reported as-is, without speculation on the internal mechanism, for maintainers to investigate further.
Environment
n8nio/n8n:2.31.0, Alpine 3.24 base, Node.js v24.16.0 inside the container)@n8n/n8n-nodes-langchain.agent(typeVersion 1.7),@n8n/n8n-nodes-langchain.lmChatAnthropic(typeVersion 1.3)claude-sonnet-5(Anthropic)n8n-nodes-base.postgresTool(a regular node used as a tool via the "usable as tool" mechanism, not a purpose-built LangChain tool node)Symptom
With a real production workflow (Twilio WhatsApp assistant), the AI Agent never calls any of its connected tools when a large static
systemMessage(~50KB, built from a business prompt template) is used. The model always finishes withstop_reason: "end_turn"(via the AI Agent's own text output — it never even attempts a tool call), narrating an intention to check something ("let me check...") and then answering from its own embedded knowledge/hallucination instead of calling any tool. No error is raised anywhere — the execution completes successfully.This was fully reproducible and is not intermittent — confirmed across all real executions retained in the database (11 days of history).
What this is NOT (ruled out with direct evidence)
system,tools,messages) that fails through the n8n AI Agent was sent directly tohttps://api.anthropic.com/v1/messages(bypassing n8n's LangChain node and our internal caching proxy entirely, using n8n'shttpRequestnode withpredefinedCredentialType) and it worked correctly (stop_reason: "tool_use"), both as a plain stringsystemand as the array-with-cache_controlformat our proxy produces.$fromAI()schema bug (tracked separately, see below) — that bug (missing explicit type argument, matching The $fromAI tool with json type is incompatible with standard JSON Schemas, leading to tools being skipped #18588) was found and fixed independently; it does not explain this symptom on its own (see Cause [feature request] Fliter events/actions in realtime #2).system-only/stringify pass, no field is dropped; confirmed via direct byte-for-byte reproduction of its output sent straight to Anthropic).cache_controlpresent or absent makes no difference at the API level, confirmed by direct testing both ways).Elimination matrix (prompt size × number of tools)
All runs below use the same isolated test workflow, same AI Agent/model config, same credential, only
systemMessagelength and the set of connected tools varied.Number of tools has zero measurable effect — only
systemMessagelength correlates with the failure.Two distinct, overlapping causes found under "large prompt"
Cause #1 — tool node missing
toolDescription(closed, root cause understood)A
postgresToolnode with nodescriptionType/toolDescriptionset at all (relying purely on default/auto behavior) fails to be included/used whensystemMessageis large. The same node, unmodified, with a shortsystemMessage, works fine — so an empty description alone is not sufficient to reproduce it; it only manifests combined with a large prompt.toolDescription?Direct-to-Anthropic confirmation: a tool schema with no
descriptionfield at all, combined with the same ~50KB system prompt and cache_control, sent straight to the Anthropic API, still resulted instop_reason: "tool_use"— the raw API tolerates a description-less tool fine, at any prompt size. So this is n8n-side behavior, not an Anthropic API constraint.Cause #2 — tool WITH a proper, well-formed
toolDescriptionSTILL fails with a large prompt (root cause NOT understood)Using a different tool (
Consultar Preço do Serviçoin our production workflow) that has a clear, well-formedtoolDescriptionstring, connected alone, with the same ~50KBsystemMessage: the tool is still never called. This rules out Cause #1 as the sole explanation — there is a second, distinct failure mode triggered by prompt size alone, independent of whether the tool has a description.We have not identified the mechanism for Cause #2. It reproduces reliably in our environment but we stopped investigating further at this point to avoid speculation without evidence.
Related but separate bug already fixed on our side (do not conflate)
Independently, we also found and fixed the known
$fromAI()issue where omitting the explicit type argument ($fromAI(key, description)instead of$fromAI(key, description, "string")) can produce a malformed JSON Schema and cause a tool to be silently skipped — this matches #18588 and community reports of"type": "None"schemas. This is a real, separate, already-understood bug that we fixed by adding the explicit type to all our$fromAI()calls. It is not the cause of the symptom described in this issue — both Cause #1 and Cause #2 above were reproduced with the type argument already correctly present.How to reproduce (minimal workflows attached)
Two exportable minimal workflow JSON files are attached in a follow-up comment on this issue (reproduces with a placeholder Postgres/Anthropic credential swapped in):
repro_causa1_tool_sem_descricao.json— singlepostgresToolwith notoolDescription, large fillersystemMessage. Fails to call the tool. SwapAI Agent.parameters.options.systemMessageto reference{{ $json.systemPromptSmall }}instead of{{ $json.systemPrompt }}to see it work.repro_causa2_tool_com_descricao.json— same setup, but the tool has a propertoolDescription. Still fails with the large prompt (Cause [feature request] Fliter events/actions in realtime #2, mechanism unknown).Both need an Anthropic credential and a Postgres credential (any reachable Postgres instance works — the query itself is trivial and only exists to give the tool a
$fromAI()parameter). Replace the placeholder credential IDs before running.To trigger: use "Execute workflow" from the n8n editor (Manual Trigger), send message "My name is Fernanda". Two complementary checks confirm whether the tool was genuinely invoked, and both were used throughout this investigation:
resultData.runData, with ametadata.subRunentry and real extracted arguments underdata.ai_tool— this confirms the model's tool-use loop actually reached that specific node. This is what the elimination matrix above is based on.inputOverride). A full-text search for the literal substring"tools"across the complete execution JSON shows whether atoolsarray was present anywhere in that call. This is the method behind this report's central finding — 0 occurrences in every failing execution we inspected, versus present (and accepted) when the same payload was sent directly toapi.anthropic.combypassing n8n. NotetoolDescription(the tool node's static config parameter) shows up regardless — that's workflow metadata, not the runtime request, and should not be confused with an actualtoolsarray in the call.Both checks agreed in every case we tested. The one thing that is not a valid signal is inferring tool use indirectly from a business-level side effect (e.g., "a database row was created, so the tool must have run") — in our production workflow a separate deterministic fallback (unrelated to the AI Agent's own tool-calling) can produce the same side effect from the model's plain text output, independent of whether any tool was actually invoked.
Summary
$fromAI()type bug (fixed separately).toolDescription+ large prompt).