Build and deploy AI-powered workflow automation by wiring n8n's agent node to LLMs, tools, and error-handling patterns — turning a visual canvas into a…
Trace the full agent loop in n8n — Trigger → Agent Node → Tool call → Observation → next decision — using a content-research workflow as the running example. You leave with a clear picture of what makes an n8n agent different from a plain automation chain.
Explains the n8n agent loop — how Trigger, Agent Node, LLM Model, and Tools wire together into a reason-act-observe cycle.
Why this matters: Understanding this loop is the foundation for every n8n AI agent workflow you build, including the SEO/GEO content-research page.
Decision this forces: Agent workflow vs. deterministic chain — when does the task need autonomous step selection?
Your n8n automation runs the same node sequence every time. But what if the right sequence depends on the data? That's where the comes in.
A plain n8n chain is deterministic: every execution follows the same wired path. An hands control to a language model. It reasons about the goal, picks a to call, reads the result, and decides next steps — repeating until done.
This reason → act → observe → repeat cycle is the . It follows the ReAct pattern: the model alternates between reasoning and external actions, using each observation to shape the next step.
Every n8n agent workflow has exactly four required building blocks. Missing any one breaks the loop.
The Agent Node is the orchestrator. It passes the goal plus prior observations to the LLM Model Node. It receives a decision ("call tool X with args Y"), executes the tool, appends the result, and loops.
Optional additions — , an , a — extend the loop but don't change its structure.
You're building an SEO content-research workflow. The goal: given a target keyword, find the top-ranking pages, pull their headings, and return a gap analysis. The steps aren't fixed — the agent decides how many pages to inspect.
Here's how the plays out turn by turn:
A deterministic chain would need every URL hard-coded and every step pre-wired. The agent chose the depth at runtime — that's the difference.
# Deterministic chain — steps hard-coded def research_workflow(keyword): results = search(keyword) # always exactly one search page = fetch(results[0]) # always the first result only return summarise(page) # done — no branching possible research_workflow("n8n ai agents")
This chain always fetches exactly one result and summarises it — the logic is baked in before the data arrives.
Predict: what happens when the top result is a forum thread with no useful headings, and the real answer is on page 3?
It summarises the forum thread and stops — it has no way to inspect results[1] or results[2]. The output is confidently wrong, and there's no error message to catch it. This is the silent failure a deterministic chain can't escape when the right path depends on the data.
# Agent loop — the model decides how many steps to take def agent_loop(goal, tools, llm): observations = [] while True: decision = llm.reason(goal, observations) # reason if decision.is_done: return decision.answer # stop result = tools[decision.tool](decision.args) # act observations.append(result) # observe agent_loop( goal="Top 3 SEO competitors for 'n8n ai agents' + gap analysis", tools={"search": search, "fetch": fetch_headings}, llm=my_llm, )
The loop runs until the LLM sets decision.is_done — the model, not the code, decides when enough data has been gathered.
Each observations.append(result) is the n8n Agent Node appending a tool result to the context before the next LLM call — this is exactly what the Agent Node does internally.
observations = [<search result: 5 URLs>]. The LLM sees the original goal PLUS that one observation. It then decides to call fetch_headings on the top URLs — the growing observation list is what lets the agent build on prior steps instead of starting fresh each time.
# Same loop — your task: fill in the missing stop condition def agent_loop(goal, tools, llm, max_steps=10): observations = [] for step in range(max_steps): decision = llm.reason(goal, observations) if ___________________________: # TODO: when should the loop stop? return decision.answer result = tools[decision.tool](decision.args) observations.append(result) return "Max steps reached — partial answer: " + observations[-1]
This is a variation of Stage 2 with a max_steps safety rail added — a real n8n agent workflow has an equivalent iteration limit.
Stop — attempt the TODO before revealing. Hint 1: the LLM signals completion via a flag on the decision object. Hint 2: you saw this flag in Stage 2.
decision.is_done
Changed lines vs Stage 2: (1) the while True became a for loop with a max_steps guard — this is the crux, because an unbounded agent loop is a real production risk (runaway tool calls, cost overruns). The is_done check is identical to Stage 2; the new safety rail is what this stage adds.
Three failure patterns account for most broken n8n agent workflows:
"No language model connected to Agent node" at execution start. Fix: wire an and confirm are set.Before trusting an AI-generated n8n agent workflow, verify: (1) the Agent Node has both an LLM Model sub-node and at least one Tool wired; (2) each tool has a clear, specific description; (3) a max-iterations limit is set; (4) the execution log shows distinct tool calls with changing arguments, not repeated identical ones.
The next module — "LLM Integration: Wiring the Brain" — covers how to connect and configure that LLM Model Node (GPT-4o or Claude) so the loop has a reliable reasoning engine.
Connect an LLM Model node (OpenAI GPT-4o as the primary example, Anthropic Claude as the swap-in) to the Agent node, set credentials, and tune temperature and max-tokens for the content-research task. You see exactly which parameters affect cost vs. quality and why the model node is separate from the agent node.
How to connect an LLM Model Node (OpenAI GPT-4o or Anthropic Claude) to an n8n Agent Node, set credentials, and tune temperature and max-tokens for a content-research task.
Why this matters: Without a correctly wired and tuned Model Node, your n8n agent has no reasoning engine — it can't decide which tools to call or produce useful output for your SEO/GEO page workflow.
The answer is the — the component that supplies the reasoning behind every decision the makes. Without it, the agent loop has no brain. It can receive a trigger and call tools. It cannot decide which tool to call or what to do with the result.
This module wires that brain in. You'll connect an OpenAI GPT-4o Model node to your content-research agent, set credentials, and tune the two parameters that control cost and quality.
n8n keeps the separate from the so you can swap providers — OpenAI, Anthropic, or others — without touching the rest of the workflow.
The Agent Node handles the loop logic. It decides when to call a tool, when to stop, and how to format the final answer. The Model Node handles one job: send a prompt to an LLM API and return the completion. Separating them means a provider change is a one-node edit, not a full rewire.
The Model Node attaches to the Agent Node via the "AI Language Model" sub-connection slot — a dedicated socket that only accepts Model nodes, not Tools or Memory nodes.
Your content-research workflow already has an Agent Node waiting. Here's the exact sequence to connect GPT-4o and make the loop runnable.
gpt-4o. Leave all other fields at their defaults for now.To swap to Anthropic Claude: delete the OpenAI Chat Model node, add an "Anthropic Chat Model" node to the same slot, enter your Anthropic API key as a new credential, and set the model to claude-3-5-sonnet-20241022. The Agent Node, Tools, and Memory nodes are untouched.
Two parameters in the Model Node control the quality-cost tradeoff: and max tokens. Temperature (0–2 scale) sets how random the model's token choices are. Max tokens caps how long the response can be — and directly caps your per-call cost.
For the content-research task, start at temperature 0.3 and max tokens 1500. That keeps the agent's tool-call decisions consistent while allowing enough output for a full page outline.
# Pseudocode: what many users try first agent_config = { "model": "gpt-4o", "temperature": 1.5, # ← too high for tool-calling "max_tokens": 8192, # ← model ceiling, not task ceiling "api_key": "sk-...", } response = call_llm(agent_config, prompt="Research SEO trends") print(response["tool_calls"]) # What do you expect here?
This config looks complete but has two silent cost traps and one reliability trap. Spot them before the fix in Stage 2.
At temperature 1.5 the model's token sampling is highly random. Tool calls require precise JSON formatting — the model frequently malforms the function-call JSON, omits required fields, or invents tool names that don't exist. You'll see either a JSON parse error in n8n's execution log or a tool call to a non-existent tool, causing the agent loop to stall. Max tokens at 8192 also means every call charges for up to 8192 output tokens even when the answer is 200 words.
# Pseudocode: corrected Model Node config agent_config = { "model": "gpt-4o", "temperature": 0.3, # deterministic enough for tool-call JSON "max_tokens": 1500, # caps cost; enough for a full outline "api_key": OPENAI_CRED, # loaded from n8n encrypted credential } response = call_llm(agent_config, prompt="Research SEO trends") print(response["tool_calls"]) # → well-formed JSON, consistent keys print(response["usage"]["total_tokens"]) # → ~400, not 8192
Two number changes — temperature 1.5→0.3 and max_tokens 8192→1500 — fix reliability and slash cost. The delta is small; the effect is large.
tool_calls now contains valid, consistently structured JSON — the model reliably picks the correct tool name and fills required fields. total_tokens drops from a potential 8192 to roughly 400 for a typical research query, cutting per-call cost by ~80%. The agent loop no longer stalls on malformed calls.
# Your turn: swap the provider to Anthropic Claude. # The agent_config below is incomplete — fill in the two missing values. agent_config = { "model": "______", # TODO: exact Claude model string "temperature": 0.3, "max_tokens": 1500, "api_key": ANTHROPIC_CRED, # already stored in n8n } # Everything below is UNCHANGED from Stage 2 — no rewiring needed. response = call_llm(agent_config, prompt="Research SEO trends") print(response["tool_calls"])
This completion rung has one gap: the model string. Supplying it correctly proves you can execute a provider swap without touching the rest of the workflow.
The missing value is "claude-3-5-sonnet-20241022". Changed lines: model field only. Temperature, max_tokens, and all downstream code stay identical — this is the whole point of the separate Model Node pattern. In n8n you'd also switch the credential reference from OPENAI_CRED to ANTHROPIC_CRED, which is a dropdown change in the node UI, not a workflow rewire.
401 Unauthorized from api.openai.com. Fix: regenerate the key with the correct scopes in the provider dashboard.Error: Could not parse tool call response and the loop stalls. Fix: lower temperature to ≤0.5 for any agent that must call tools.finish_reason in the execution log. If it reads length instead of stop, raise max_tokens.gpt-4-0613. Confirm the string against the provider's current model list.finish_reason: stop, not an auth error.With the Model Node wired and verified, the next module focuses on what you send into it: writing the system prompt that scopes your research agent's role, enabling Window Buffer Memory to carry context across turns, and setting a structured JSON output format.
Write a system prompt that scopes the content-research agent's role, enable Window Buffer Memory to carry conversation context across turns, and set a JSON output parser so downstream nodes receive structured data. You complete a partially written system prompt and fix a broken output-parser schema.
How to configure an n8n Agent Node's system prompt, Window Buffer Memory, and JSON output parser for a structured content-research workflow.
Why this matters: These three settings are what turn a raw LLM connection into a focused, stateful agent whose output your downstream nodes can actually use — essential before adding tools.
Answer: (how random the sampling is — lower = more focused) and max-tokens (the hard ceiling on reply length). Those two parameters shape the raw output. This module adds the layer above them: the that scopes the agent's role, the memory that carries context across turns, and the output parser that makes the result machine-readable.
Together, prompt + memory + parser turn a general-purpose LLM into a focused, stateful, structured agent — the configuration layer that sits between the model and your workflow.
The is the first message the sends to the model on every turn — before the user message, before any tool results.
A well-scoped system prompt does three things: it names the agent's role, it constrains what the agent should and should not do, and it specifies the output format. Without it, the model answers as a general assistant and ignores your downstream schema.
For a content-research agent, the prompt must tell the model it is a researcher (not a writer or a coder), that it should cite sources, and that it must return a specific JSON shape — not prose.
SYSTEM PROMPT (incomplete — missing output contract): You are a content-research agent for SEO/GEO pages. Given a target query, find the top facts, entities, and source URLs relevant to that query. Do NOT write the final page copy — research only. Always verify claims before including them. [output contract missing here]
This prompt scopes the role and constraints but omits the output contract — so the model returns whatever format it likes.
The agent returns a freeform prose paragraph — something like: "n8n AI agents are workflow automation agents built on the n8n platform. Key facts: n8n supports OpenAI GPT-4o... Sources: n8n.io/blog/..."
No JSON keys, no consistent structure. The downstream node that expects { "facts": [...], "sources": [...] } receives a plain string and either errors or silently passes the whole blob as one field. The output contract is what forces structure — without it, every run looks different.
You are a content-research agent for SEO/GEO pages. Given a target query, find the top facts, entities, and source URLs relevant to that query. Do NOT write the final page copy — research only. Always verify claims before including them. Respond ONLY with valid JSON matching this schema: { "query": "<the original search query>", "facts": ["<fact 1>", "<fact 2>"], // TODO: add the sources key "entities": ["<entity 1>", "<entity 2>"] }
Stop — attempt the TODO before revealing. The missing key is the one downstream nodes need to attribute claims. Add it to the schema with the right value type.
Hint 1: the role line says 'cite sources'. Hint 2: a source is a URL string, and there can be more than one.
"sources": ["<url 1>", "<url 2>"]
Changed lines: one new key added after 'entities'. The value is an array of strings (URLs), matching the role constraint 'cite sources'. The downstream JSON parser now has all four keys it needs: query, facts, entities, sources.
stores the last N's context. It then drops older turns as new ones arrive.
In n8n, you attach it in the Agent Node's Memory slot and set the Window Size — the number of past human+AI turn pairs to retain. A window of 5 keeps the last 5 exchanges; everything before that is gone from the model's view.
The tradeoff is direct: a larger window gives the agent more context for multi-turn research tasks, but each retained turn adds tokens to every subsequent call — raising both latency and cost.
sits between the Agent Node's raw text reply and the next node in your workflow. In n8n, you attach a JSON Output Parser in the Agent Node's Output Parser slot and paste the expected schema.
The parser validates the model's reply against the schema and either passes structured data downstream or throws a parse error. This is what makes the agent's output machine-readable — without it, every downstream node receives a raw string.
json and ends with ``. The parser sees a string, not an object, and throws: "SyntaxError: Unexpected token ` in JSON at position 0". Fix: add "Return raw JSON only, no markdown fences" to the system prompt."sources" when it finds no URLs. The parser throws: "Validation error: required property 'sources' missing". Fix: mark optional keys as nullable in the schema, or instruct the model to return an empty array."facts": "one fact" (a string) instead of an array. Some parsers coerce it silently; downstream nodes then fail when they try to iterate. Observable symptom: the workflow runs green but the Set node that maps facts[0] returns undefined. Fix: specify type: array explicitly in the schema and test with a short research query first.Your content-research agent now has a clear identity (system prompt), a rolling memory of the last 5–8 turns (Window Buffer Memory), and a validated JSON output. Downstream nodes can read it without guessing.
Here is what that looks like end-to-end in a single research session:
{ "query": "n8n AI agents", "facts": [], "entities": [], "sources": [] }The gap between turn 2 and turn 3 is exactly what the next module closes. Adding an HTTP Request tool (SerpAPI for live search) and a Code tool (a Python snippet to parse results) gives the agent the hands it needs to fetch and process real-world data.
If you used an AI assistant to draft your system prompt or parser schema, run these checks before wiring it into the workflow:
Add three tool types to the content-research agent — an HTTP Request tool (SerpAPI for live search), a Code tool (Python snippet to parse results), and an n8n-native Send Email tool — and define each tool's description so the LLM knows when to call it. You finish a partially wired HTTP tool and write its description string.
Attach HTTP Request, Code, and n8n-native action tools to an Agent node, write effective tool descriptions, and test each tool in isolation.
Why this matters: Your content-research agent is useless without tools — this module gives it the ability to fetch live search data, parse it, and send results by email, which are the core actions your SEO/GEO page workflow depends on.
Decision this forces: Custom HTTP tool vs. n8n-native node as a tool — which gives more control and when does it matter?
The sets the agent's role, scope, and output format — it tells the model who it is and what it should produce. Tool descriptions, by contrast, tell the model what actions are available and when to reach for each one. Both are required: the system prompt without tools gives the agent no hands; tools without a clear system prompt give it no judgment.
Module 3 left the agent with a brain and a memory. This module gives it hands — three tool types that let it fetch live data, process it, and act on it.
Your content-research agent needs three capabilities: fetching live search results, parsing raw JSON into clean data, and sending a summary by email. Each maps to a different tool type inside the .
All three attach to the same Agent node via the Tools socket. The agent decides which to call based on the you write for each one — not on position or order.
Imagine the agent receives this goal: "Research the top 5 SEO trends for 2025 and email a summary to the editor."
On its first reasoning step, the model reads all three tool descriptions. The HTTP Request tool says: "Use this to search Google for live results via SerpAPI. Input: a search query string." That matches the current sub-goal, so the agent calls it first.
The raw SerpAPI response comes back as nested JSON. The Code tool says: "Use this to parse and clean SerpAPI JSON into a list of {title, url, snippet} objects." The agent recognises the observation matches and calls the Code tool next.
Finally, the Send Email tool says: "Use this to send an email. Input: recipient, subject, body." The agent calls it once the summary is ready. A vague description — like "does email stuff" — causes the model to skip or misuse the tool.
# HTTP Request tool config (pseudocode matching n8n field names) http_tool = { "name": "search_google", "description": "Search Google for live results via SerpAPI. " "Input: a search query string. " "Use when you need current web data.", "method": "GET", "url": "https://serpapi.com/search", "params": { "q": "{{ $input.query }}", # agent fills this "api_key": "{{ $credentials.serpApiKey }}" } }
This shows the three fields that matter most in an HTTP Request tool: name, description, and the params that the agent populates at runtime.
The description is the agent's decision signal — it must name the tool's purpose, its expected input, and the condition for using it. The {{ $input.query }} placeholder is filled by the LLM's tool-call argument, not by you.
The LLM generates a tool-call JSON like {"query": "SEO trends 2025"} and n8n substitutes that into {{ $input.query }}, so the GET request goes out with q=SEO+trends+2025. The agent supplies the argument — you only define the slot.
# Code tool — Python snippet run inside n8n's sandbox def run(input_data): results = input_data.get("organic_results", []) cleaned = [ {"title": r["title"], "url": r["link"], "snippet": r["snippet"]} for r in results[:5] ] return {"items": cleaned}
The Code tool receives the raw SerpAPI JSON as input_data and returns a clean list the agent can reason over. Keeping the output schema simple — a list of flat dicts — reduces the chance the LLM misreads the structure.
Python raises a KeyError on r["snippet"] and the Code tool returns an error observation to the agent. The agent loop sees the failure and may retry or report it. Fix: use r.get("snippet", "") to default to an empty string.
# Near-complete Send Email tool config — fill in the TODO email_tool = { "name": "send_summary_email", "description": # TODO: write a description that tells the agent # (1) what this tool does, (2) what inputs it needs, # (3) WHEN to call it (not before the summary is ready). "to": "{{ $input.recipient }}", "subject": "{{ $input.subject }}", "body": "{{ $input.body }}" }
Stop — attempt the TODO before revealing. The description string is the only missing piece; the field mappings are already correct.
"Send an email to a recipient with a subject and body. Input: recipient (email address), subject (string), body (string). Use this ONLY after the research summary has been compiled — do not call before the content is ready."
--- Changed lines vs. Stage 1 ---
| Option | Control over request | Setup effort | When to choose | Cost | Complexity |
|---|---|---|---|---|---|
| Custom HTTP Request tool | Full — set any header, param, body, or auth | Higher — manual field mapping required | When you need custom headers, auth schemes, query params, or the target API has no n8n node. | No extra cost; uses your own API credentials. | Medium — you configure URL, method, params, and credentials manually. |
| n8n-native node as tool | Limited to the node's exposed fields | Lower — credential connect + field fill | When n8n already has a node for the service (Gmail, Slack, Notion, etc.) and the default fields cover your use case. | No extra cost; uses n8n's built-in node. | Low — connect credentials and the node handles the API shape. |
The agent receives an error like KeyError: 'snippet' and may loop or halt. Use .get(key, default) for every field you don't control.With all three tools wired and verified, your agent can research, process, and act. The next module shows how to compose multiple agents into sequential chains and parallel splits.
Implement three patterns on the n8n canvas using the content-research scenario: a sequential chain (research → draft → review), a parallel split (two agents run simultaneously then merge), and a supervisor-worker multi-agent setup where a planner agent routes sub-tasks. You revisit the agent loop from Module 1 to explain why the supervisor pattern needs its own memory scope.
Teaches three multi-agent composition patterns on the n8n canvas — sequential chain, parallel split, and supervisor-worker — using the content-research workflow as the running example.
Why this matters: Knowing which topology to pick lets you build SEO/GEO page workflows that are faster, cheaper, and easier to debug — and sets you up to harden them in the final module.
Decision this forces: Sequential vs. parallel vs. supervisor-worker — which topology fits the task's dependency structure?
The three tools were: an (SerpAPI for live search), a (Python to parse results), and an n8n-native Send Email tool. Each tool's tells the LLM when to use it.
Now the question shifts: you have one capable agent. What happens when the task is too big, too slow, or too complex for a single loop? This module answers that.
Every multi-agent answers one question: do the sub-tasks depend on each other, and if so, who decides the order?
Picking wrong multiplies latency and cost without adding capability — five agents where one loop suffices is a common trap.
The content-research workflow maps cleanly onto a sequential chain because each stage depends on the previous one's output.
On the n8n canvas, each agent is a separate connected by a wire. The on the Research Agent ensures the Draft Agent receives clean JSON, not raw prose.
Total latency is additive — if each agent takes 8 s, the chain takes ~24 s. That's the cost of strict dependency.
# Each agent is a function wrapping an LLM call + tools research_result = research_agent.run( input=keyword, # e.g. "best noise-cancelling headphones 2025" tools=[serpapi_search] ) draft_result = draft_agent.run( input=research_result["summary"], # structured JSON from step 1 tools=[] ) review_result = review_agent.run( input=draft_result["text"], # plain-text draft from step 2 tools=[] )
Each agent's output feeds directly into the next agent's input — this is the sequential chain in code form.
Notice that only the Research Agent has tools; the Draft and Review agents reason over text alone, which keeps their focused and their latency low.
The Draft Agent receives an unstructured blob. Without field names like "summary" or "sources", it may hallucinate structure or produce a draft that ignores key facts. This is why the Output Parser on the Research Agent is non-negotiable — it enforces the contract between agents.
| Option | Task dependency | Latency profile | Routing flexibility | When to choose | Cost | Complexity |
|---|---|---|---|---|---|---|
| Sequential Chain | Strict — step N+1 needs step N's output | Additive — total time = sum of all steps | Fixed order; no dynamic branching | When each step needs the previous step's output — e.g. research → draft → review. | Low (one agent runs at a time) | Low |
| Parallel Split | None between parallel branches; merge at end | Near-constant — total time ≈ slowest branch | Fixed split; branches defined at design time | When sub-tasks are independent and you want to cut wall-clock time — e.g. two research agents covering different sources simultaneously. | Medium (concurrent LLM calls) | Medium |
| Supervisor-Worker | Handled dynamically by the supervisor | Variable — depends on planner decisions | Fully dynamic; planner routes at runtime | When the decomposition is dynamic — the planner decides at runtime which workers to invoke and in what order. | High (planner LLM call + N worker calls) | High |
In a , n8n fans out to two Agent Nodes simultaneously. A Merge node waits for both before continuing. Wall-clock time drops to roughly the slowest branch.
The pattern adds a planner agent. It reads the goal and emits routing decisions at runtime. It can call workers sequentially, in parallel, or skip them entirely.
Critical point: the supervisor needs its own scope, separate from each worker. If workers share the supervisor's memory, their intermediate outputs pollute the planner's reasoning context and cause drift.
def supervisor_agent(goal: str, worker_registry: dict) -> str: plan = planner_llm.call( system="You are a planner. Return a JSON list of worker names to call in order.", user=goal ) results = {} for worker_name in plan["steps"]: worker = worker_registry[worker_name] results[worker_name] = worker.run( input=goal, context=results # pass prior results as context ) # TODO: add the merge step that synthesises results into a final answer return ???
The supervisor calls a planner LLM to decide which workers to invoke, then runs them in order, accumulating results.
The TODO is the merge step — the part that turns individual worker outputs into a single coherent answer. This is the crux of the supervisor pattern.
# Changed lines flagged with ★
return planner_llm.call( # ★ reuse the same LLM
system="Synthesise the worker outputs into a final answer.",
user=f"Goal: {goal}\nResults: {results}" # ★ pass goal + all results
).get("answer", "") # ★ extract the answer field
# Why this matters: without a dedicated synthesis call, the supervisor has no
# step that actually combines outputs — it just returns the last worker's result,
# silently dropping everything else. The merge is where the pattern pays off.
undefined. Fix: enforce an on every agent whose output feeds another agent.plan["steps"] and confirm it never exceeds your cap.Module 6 picks up exactly here: you'll add retry logic (up to 3 attempts with exponential backoff) to the HTTP tool call. Wire an Error Trigger fallback branch that fires a Slack alert when any agent in the chain fails. This hardens the workflow from a working prototype into something production-ready.
Add retry logic (max 3 attempts, exponential backoff) to the HTTP tool call, wire an Error Trigger fallback branch that sends a Slack alert, and read the n8n execution log to diagnose a tool-call failure in the content-research workflow. You also learn the three most common n8n agent failure modes and how to spot each in the logs.
Harden an n8n agent workflow with retry logic, an Error Trigger fallback, and execution-log diagnosis.
Why this matters: A production SEO/GEO workflow that silently fails or never alerts you costs rankings and deadlines — this module makes failures visible and self-healing.
Answer: the merges whatever it received — including the empty result — and the final output is silently incomplete. No error is raised, no alert fires, and the user sees a half-researched page. That gap is exactly what this module closes.
You've built the full content-research workflow across five modules. Now you need to harden it: add retry logic so transient failures self-heal. Wire a fallback branch so persistent failures alert a human. Learn to read the to diagnose what actually broke.
Every n8n agent failure traces back to one of three origins. The names the culprit node directly.
ERROR in node "SerpAPI Search": 429 Too Many Requests. Fix: add retry logic with exponential backoff.ERROR in node "OpenAI Chat Model": 503 Service Unavailable or maximum context length exceeded. Fix: retry for 503; reduce or trim the system prompt for context errors.ERROR in node "Output Parser": SyntaxError: Unexpected token. Fix: tighten the instruction to enforce JSON. Or lower to reduce creative deviation.n8n's lives on each node's Settings panel. Set Max Retries to 3 and Retry Interval to exponential (1 s → 2 s → 4 s). Three attempts cover most transient API blips without burning your rate-limit budget.
The key tradeoff: more retries increase total latency and can worsen a rate-limit spiral. Cap at 3 and escalate to a human after that — don't silently swallow the error.
Apply retries to the (SerpAPI) and the LLM Model node. The node does not benefit from retries — its failures are structural, not transient.
It's 2 a.m. and your scheduled content-research workflow fires. SerpAPI returns 429 Too Many Requests on the first attempt — a burst from another tenant hit the shared rate limit.
With retries configured (max 3, exponential backoff), n8n waits 1 s and retries. The second attempt succeeds. The execution log shows two entries for the SerpAPI node: one red (attempt 1, 429) and one green (attempt 2, 200). The workflow completes normally and no Slack alert fires.
Now imagine SerpAPI is down for 10 minutes. All three retries fail. n8n marks the execution as Error and the fires a separate workflow. It posts a Slack alert: "Content-research failed after 3 retries — SerpAPI node, execution #4821." A human can now intervene before the page deadline.
# n8n node settings — applied to the SerpAPI HTTP Request node node_settings = { "retryOnFail": True, "maxTries": 3, "waitBetweenTries": 1000, # ms — first wait "backoffStrategy": "exponential", # 1s → 2s → 4s "continueOnFail": False, # halt and trigger Error Trigger }
These five fields map directly to n8n's node Settings panel. continueOnFail: False is the critical choice: it lets the fire instead of silently passing a null value downstream.
The node passes an empty/null items array downstream and the execution log marks the node GREEN (not red). The workflow appears to succeed, but the agent receives no search results and may hallucinate content. This is the silent failure mode — continueOnFail: True hides the error.
# Separate n8n workflow: "Content-Research Error Handler" # Trigger: Error Trigger node (catches any failed execution # in the main content-research workflow) error_payload = { "workflow": "{{ $json.workflow.name }}", "execution_id": "{{ $json.execution.id }}", "failed_node": "{{ $json.execution.lastNodeExecuted }}", "error": "{{ $json.execution.error.message }}", } # Next node: Slack → post error_payload to #seo-alerts channel
The is a separate workflow, not a branch inside the main one. It receives the full error context automatically — workflow name, execution ID, the last node that ran, and the error message — so your Slack alert contains everything needed to diagnose the failure without opening n8n.
Add: "status_code": "{{ $json.execution.error.message.split(' ')[0] }}"
Changed line: extracts '429' from '429 Too Many Requests' so the Slack alert shows the numeric code, making triage faster. The rest of the payload is unchanged.
In n8n, go to Executions → find the red row → click it. The canvas opens with each node colour-coded: green = success, red = error, grey = never reached.
Click the first red node. The right panel shows Input, Output, and Error tabs. The Error tab gives the raw message — e.g. ERROR: 429 Too Many Requests. This tells you the failure is a tool-call failure (HTTP), not an LLM or parser failure.
Click the → Output tab → expand "Intermediate Steps". Each tool call the agent attempted is listed with its input and the raw response. If the agent retried a tool internally before the node-level retry fired, you'll see multiple entries here.
If the Agent Node is green but the Output Parser node is red, the LLM responded but produced malformed JSON. Check the Agent Node's Output → "text" field: if it contains prose instead of a JSON block, lower and add an explicit JSON instruction to the .
After applying the fix, use "Retry execution" (top-right of the execution view). All nodes re-run from the failed node forward — you don't need to re-trigger the whole workflow. Verify every node turns green and the Output Parser's output tab shows a valid JSON object.
If you used an AI assistant to generate your retry settings or Error Trigger workflow, check these four things before going live:
continueOnFail is False on every retried node. AI tools often default it to True; this silently swallows errors.With retries, a fallback branch, and log-reading skills in place, your content-research agent is production-ready. The capstone challenge asks you to build a solo variation — a new workflow with a different tool set. Apply every pattern from all six modules end to end.
Before reading the summary, reconstruct from memory: what are the four required nodes in every n8n agent workflow, what is the order of the build steps from architecture to production hardening, and which pattern — sequential, parallel, or supervisor-worker — would you choose if two research sub-tasks have no dependency on each other?
Apply what you learned to SEO/GEO page — the page title is the H1 and the exact search query. OPEN with a 40-60 word self-contained, quotable answer capsule that names the entity explicitly in sentence one (no "in this lesson…" preamble) — this is the sentence an LLM lifts. Name the entity by its full name every time (not pronoun-only). Structure each section as ONE sub-question (How it works · X vs Y · When to use it · Example · Common mistakes), each opening with its own 1-2 sentence direct answer then depth. End with a genuine 3-5 question FAQ phrased as real user questions ending in "?" (these become FAQPage schema + the knowledge check). Prefer quotable specifics — concrete numbers, defaults, version names, one short snippet — over vague prose. Self-contained for a reader who arrived cold from a search engine or an LLM. Intent = explainer: mechanism + example + when-to-use. Target query: "n8n ai agents"..
Which statement best describes when you should choose an n8n agent workflow over a deterministic n8n chain?
An n8n agent workflow is the right choice when the task's required steps cannot be fully enumerated upfront — the agent reasons about what to do next after each observation. A deterministic chain is better when every step is fixed and predictable, giving faster and cheaper execution. API count and latency alone do not determine which pattern to use.
In your own words, describe the n8n agent reasoning loop. Name each phase in order and explain what happens between the Agent node and a Tool node during one cycle.
The four phases — reason, act, observe, repeat — are the core of the ReAct-style loop n8n agents implement. Understanding that the tool result feeds back into the next reasoning step (not just appended to output) is what distinguishes an agent from a simple chain.
Consider this n8n agent system prompt snippet:
"You are a JSON-only responder. Always reply with {\"result\": <value>}. Never add explanation."
What is the PRIMARY purpose of writing the system prompt this way?
A system prompt that mandates a strict JSON schema is the mechanism that makes the agent's output machine-readable for a downstream JSON output parser. Temperature and max-tokens are LLM Model node settings, not system prompt effects. The system prompt does not suppress tool calls — tool availability is controlled by which Tool nodes are attached.
You are building an n8n agent that must fetch live data from a REST API that has no pre-built n8n integration. Which tool approach gives you the most control over request headers, authentication, and response parsing?
A custom HTTP Request tool node lets you specify every aspect of the request — method, headers, auth credentials, query params, and response handling — making it the right choice when no native n8n node exists for the target API. Native action nodes are faster to configure but only exist for supported services. Window Buffer Memory stores conversation history, not API responses. Embedding API logic in the system prompt is unreliable and bypasses n8n's credential management.
You have a multi-agent n8n workflow where Agent A's output is required as input to both Agent B and Agent C, and both B and C must finish before Agent D can run. Which topology fits this dependency structure?
Because B and C both depend on A's output but are independent of each other, running them in parallel reduces total latency compared to a sequential chain. A merge node then gates D until both B and C complete. A supervisor pattern adds unnecessary routing overhead when the dependency structure is already known. Collapsing everything into one agent with four tools loses the isolation and parallelism benefits.