Error Handling
Handle timeouts, no-reply, and unexpected input so flows fail gracefully.
Real conversations don't always go to plan: an API is slow, a caller doesn't respond, a value isn't what you expected. Account for these paths instead of leaving them unwired. A node's exits are the alternate paths it exposes when something doesn't take the happy path.
Timeouts on external calls
The Integration, Invoke Lambda, and SharpenDB nodes expose a timeout exit that
the flow takes when the call doesn't complete in time:
- Integration — the node's Timeout, capped at 25 seconds whatever you enter.
- Invoke Lambda — the node's Timeout plus one second, and never more than 28 seconds, so any
Timeout of 27 or more takes
timeoutat 28 seconds. - SharpenDB nodes — 20 seconds. The node's Timeout field is not applied and does not change that limit.
An Invoke Lambda function that hits its own configured Lambda timeout before the node stops
waiting takes fallback instead. See
AWS.
Always wire timeout to something deliberate: a fallback message, a retry via a
second attempt, or a transfer to a live agent. An unwired timeout falls through to the
node's fallback exit, so a slow dependency and a failed one then take the same path.
Each node's reference page lists its exits, including timeout and
any other non-default paths, so you can see exactly what needs wiring.
No reply and repeated prompts
Voice interactions have their own failure modes:
- Play Message can repeat a prompt a set number of times; when the repeats
are exhausted it takes the
repeatLimitReachedexit. Wire it to handle a caller who never responds — reprompt differently, or transfer out. - Gather input into a variable and then validate it with a Condition before acting on it, rather than assuming it's well-formed.
Unexpected values
When you branch on data — especially data from a caller or an external system — make sure there's a path for values you didn't anticipate:
- Switch routes to the exit for the first matching case. Wire its
defaultexit so an unmatched value still goes somewhere sensible. - Condition always resolves to
trueorfalse; make sure both are wired when both outcomes need handling.
Failures inside a loop
A Loop Group claims every unhandled outcome from a node inside it, whatever that outcome
is. A member whose exit is wired to nothing sends the flow back to the group, and the next
element starts. That is how the container form iterates, and it applies to a node's
fallback and invalidInput exits exactly as it applies to its default one.
The consequence for error handling: a body node that fails and has nothing wired does not stop the run, and does not report anything. It silently starts the next iteration. Wire the failure exits on nodes inside a loop body, or wrap them (see below).
To leave a loop early on purpose, put a Loop Break node inside the Loop Group and wire
the body to it. Running it abandons the remaining elements and sends the flow out the
group's own break exit. Loop Break has no fields and no onward wire of its own: wire the
group's break exit to wherever recovery should continue. Outside a Loop Group, Loop Break
has no loop to stop and takes invalidInput instead. See
Loops.
Try / Catch around a loop body
Try / Catch is a container. Anything inside it that takes an invalidInput or
fallback exit nothing inside handles routes to the group's catch exit instead of ending
the run. Turn on Catch every unhandled exit to catch other outcomes too, such as an
unwired timeout. In the catch branch, $(sys.error.node), $(sys.error.exit), and
$(sys.error.message) say what failed. A node that wires its own exit keeps it: local
handling always wins over the group.
Which group claims a failure is decided by which one is nearer, walking outward from the node that failed, and a Loop Group stops that walk because it claims everything. So nesting order decides the behavior:
- Try / Catch inside the Loop Group — the Try / Catch is nearer, so it catches the
failure and the
catchbranch runs. Pointcatchat a node that continues the iteration and the loop carries on with the remaining elements. - Loop Group inside the Try / Catch — the Loop Group is nearer and claims the failure
first, so it starts the next iteration and the outer
catchnever runs. An outer Try / Catch protects the loop node itself, not the nodes in its body.
Put the Try / Catch inside the loop when you want per-element recovery. That is almost always what you want.
Don't point a Loop Group's onFinished or break exit, or a Try / Catch's catch exit, back
into the group it belongs to. A catch inside its own try block catches its own failure again;
a Loop Group's exits leading back into its body reopen the iteration from the first element.
Either way the flow runs until it hits the workflow's node-execution limit. Verify reports both
as warnings.
Ending a path cleanly
Not every branch continues the conversation. Use Disconnect to end a voice call deliberately (for example after an after-hours message), and Response to return a result and end a flow invoked for its output. A path that just ends with an unwired exit works, but an explicit terminal node makes the intent clear.