[Tutorial] Fixing "Failed to parse agent steps" with Basic LLM Chain and Structured Output Parser

I recently built an AI-powered client intake classifier (documented in my showcase post here: Built a client intake classifier with n8n — five categories, a retry layer, and a redesign I didn't plan for ).

The workflow takes a form submission, uses an LLM to classify the inquiry into a specific category, and then routes it to a category-specific email and a shared Sheets log. It works now, but getting there involved hitting a few specific walls. I am documenting the biggest one here, along with a few structural things I learned during the build, in case it helps someone else running into the same issues.

The Bug: “Failed to parse agent steps”

When I connected a Basic LLM Chain node to a Structured Output Parser node, the execution failed. The exact error was:

Failed to parse agent steps

My first instinct was that I had formatted my JSON schema or my prompt incorrectly. But before blindly tweaking the prompt, I checked the raw model output first. I found that the LLM’s actual answer was perfectly fine. The issue was that my Structured Output Parser was still holding onto an old schema from an earlier iteration.

I fixed the schema, but it still failed with the exact same error.

That sent me digging deeper, and I found out this one wasn’t a prompt issue at all. It is a documented bug in n8n itself (issue #29903 / PR #33338). The root cause is a @langchain/core ESM and CommonJS double-load that breaks the instanceof BaseMessage check under the hood. Because the Basic LLM Chain was routing output through logic meant for AI Agents, it broke structured parsing even when the model’s response was completely correct.

The solution: Update n8n. The fix was shipped in version 2.30.0 (released July 7, 2026) and backported to the 2.29.4 beta. Updating resolved it immediately. (Note: This was also discussed and confirmed in this thread: Failed to parse agent steps )

Other Learnings from the Build

While debugging the parser, I also ran into a few structural issues in how I was moving data around. Here is how I resolved them:

1. The “Retry On Fail” time limit
I wanted the LLM chain to retry automatically if it hit a rate limit or temporary failure. I used the built-in Retry On Fail setting on the node (set to 3 attempts). However, I noticed the wait time between tries wouldn’t go above 5 seconds.

I learned that n8n enforces a hard cap of 5000ms (5 seconds) on the wait-between-tries for this built-in setting. This is intentional to prevent long retries from freezing worker threads. If you need a longer wait (like 10 seconds), you cannot use the built-in node setting; you have to build a custom branch or loop.

2. Action nodes overwriting item data (and how to decouple it)
When I added the Gmail node to send the category-specific emails, it overwrote the item data with its own send-confirmation output. My original form data (Name, Email, description) was gone by the time it reached the final step.

My initial thought was to just branch the workflow before the Gmail send. But the cleaner architectural fix was to decouple the data flow entirely. I realized the shared Sheets logging didn’t actually need to happen after the emails. I moved the Sheets node upstream, right after classification, before any branching or emails happen.

For the specific branches where data still needed to flow through an action node, I added a Set node immediately after to rebuild one clean, flat object, so everything downstream just reads from a predictable structure.

3. JSON schema field ordering forces LLM reasoning
When using the Structured Output Parser, I assumed the order of the fields in the JSON schema didn’t matter. It does, and it affects the model’s logic in a very specific way.

I had category listed before reasoning in my schema. This structurally forced the model to output its final category answer before it was allowed to write the reasoning that was supposed to inform it. It was essentially guessing before thinking. Reordering the schema fields so reasoning comes first completely fixed the consistency of the classifications.

1 me gusta