Most AI workflows look great in demos. Clean input, clean output, everyone's happy.
Then real data shows up. A user submits something unexpected. An API returns a weird format. A field is missing. And the whole thing either silently fails or produces garbage that nobody catches until a client asks why something's wrong.
That's not an AI problem. That's a logic problem. Specifically, it's a branching problem.
Here's the system I use to handle edge cases before they become fires.
Why Most Workflows Are Fragile
When you build with Claude, n8n, or Make.com, you're usually optimizing for the happy path. The input looks like you expect. The model does what you want. The output lands where it should.
But in production, the happy path is maybe 70% of what actually happens. The other 30% is edge cases. Incomplete data. Ambiguous inputs. Unexpected formats. Timeouts. Empty arrays.
If your workflow has no branching logic, it treats all of that like the happy path and produces wrong results confidently. Which is worse than failing loudly.
The Three Layers of Branching I Use
I think about branching in three distinct layers. Each one catches a different class of problem.
Layer 1: Input Validation Before Anything Runs
Before any AI node fires, I run a validation step. This is usually a simple function node in n8n or a filter step in Make.com. It checks for the fields I actually need.
Not just "does this field exist" but "does this field have usable content." An empty string passes existence checks. It still breaks your prompt.
I set three possible outputs from this layer: clean, repairable, and dead.
- Clean means the input looks right, pass it through.
- Repairable means something's off but I can normalize it before the AI sees it. Wrong format, extra whitespace, a field that came in as a number when I expected a string.
- Dead means the input is too broken to fix automatically. Route it to a human review queue, log it, and stop.
Most builders skip the repairable category entirely. They just pass or fail. That middle layer saves a lot of workflows from dying on minor formatting issues.
Layer 2: Output Validation After the Model Responds
The model ran. Now what did it actually return?
I always validate AI output before it touches anything downstream. Claude is generally consistent, but "generally" isn't good enough in production. It occasionally returns a different structure. It occasionally adds explanation text when you only wanted JSON. It occasionally refuses parts of a request.
My output validation checks three things:
- Is it the right format? If I asked for JSON, is this actually parseable JSON?
- Are the required keys present? Not just any response, the specific fields I need downstream.
- Does the content pass a basic sanity check? Not empty. Not a refusal. Not a hallucinated non-answer.
If it fails any of these, I don't retry blindly. I route to a repair prompt that gives Claude the bad output and asks it to fix the specific problem. One retry with context. If it fails again, it goes to the dead queue.
Layer 3: Downstream Dependency Checks
This one most people never build until something breaks badly.
Even if input is clean and output looks valid, the downstream systems your workflow connects to can fail. An API is rate-limited. A database write fails. A webhook endpoint is down.
I add a dependency check after every external write. If the write fails, I don't just log it and move on. I check whether the failure is recoverable (retry in 60 seconds) or terminal (log, alert, stop).
The decision is simple: if the failure could cause data inconsistency or a silent wrong state downstream, it's terminal. Stop the workflow. Alert me. Don't let it cascade.
How This Looks in Practice
Here's a real example. I have a workflow that takes inbound client form submissions, extracts structured data with Claude, then writes that data to a CRM and sends a Slack notification.
Before I added branching logic, it would occasionally write partial records to the CRM when Claude returned malformed JSON. No error. No alert. Just bad data sitting in the database.
After I added the three layers, the same bad input now hits the validation step, gets flagged as dead, routes to a review queue in Notion, and sends me a Slack message with the raw input. I fix it manually in under two minutes. The CRM stays clean.
The workflow runs maybe 200 times a month. About 15 of those hit some kind of edge case. Before branching, those 15 were silent failures. Now they're visible, fixable, and logged.
The Tools I Use for This
In n8n, I use Switch nodes for branching and Set nodes to normalize data before it hits the AI node. Function nodes handle the more complex validation logic where I need to write actual JavaScript.
In Make.com, I use Router modules with filter conditions on each branch. Less flexible than n8n for complex logic, but plenty capable for most branching patterns.
For the AI layer, I always ask Claude to return a structured response with a status field. Something like a top-level "success" boolean and an "error" string if something went wrong. That gives me a machine-readable signal I can branch on, separate from the actual output content.
The prompt for that looks roughly like: return your response as JSON with a "status" field set to "ok" or "error", an "error_reason" field if status is error, and your actual output in a "result" field. That structure alone catches a lot of problems early.
The full repair prompt structure, the dead queue setup, and the normalization map pattern are all in the Inner Circle breakdown for this post. If you're building workflows that need to actually hold up in production, that's where to start.