Failure handling
Retries, error routing and timeouts are settings on the individual node, not on the workflow. They sit in the node inspector under Execution settings, separate from the node's own options, and they are what turns "the import broke" into something an operator can read.
{
"id": "fetch-orders",
"nodeSlug": "revenexx:http-request",
"nodeVersion": "1.1.0",
"config": {
"method": "GET",
"url": "${{ vars.erpBaseUrl }}/orders"
},
"retry": { "maxAttempts": 5, "backoffSeconds": 2, "strategy": "exponential" },
"timeoutSeconds": 120,
"onError": "route"
}
Retries
A node may declare retry with three fields:
| Field | Range | What it does |
|---|---|---|
maxAttempts | 1–100 | Total attempts, not retries after the first. 1 means do not retry. |
backoffSeconds | — | The initial wait before the second attempt. |
strategy | linear or exponential | Whether the wait stays proportional or doubles. |
Absent a retry block, the engine default applies: three attempts, exponential backoff.
Retry the things that fail transiently — a network hiccup, a rate limit, a file server that dropped a connection — and do not retry things that will fail the same way every time. A malformed record does not become well-formed on the third attempt; it just delays the failure by the backoff.
Be careful with retries on a node that writes. An attempt that timed out may have succeeded on the far side, so a retried write needs to be idempotent — key it on something stable from the data rather than on the fact of the attempt.
onError: what happens after the retries are exhausted
Two values:
fail(the default) — the run fails.route— the failure is recorded on the node's reservederroroutput port, so a wired error edge handles it.
The error port is reserved: it is the same channel a node uses for its own expected failures, which is why an error path looks like any other path on the canvas. A node with an unwired error port and onError: "route" swallows the failure — the run continues with nothing on that branch — so wire it.
Routing failures rather than failing the run is what turns "the import broke" into "the file moved to the failed folder and the run finished". The shape to copy:
- The working step's
errorport goes to a Move File node that puts the file in a failed folder. - That goes to a Send Email node, or an HTTP call into whatever your team actually watches.
- Optionally, then a Stop and Error so the run itself is marked failed after the cleanup has happened.
That last step is the difference between a legible failure and a silent one. A run that routed its error and then finished green looks successful in the run list.
Timeouts
timeoutSeconds bounds a single node's execution, between 1 and 7200 seconds. The default is 10 minutes.
- Raise it for orchestration nodes that wait on somebody else's job — a gigabyte catalog import is a normal case for a two-hour timeout.
- Lower it for a call that should fail fast. A node that waits ten minutes on a dead endpoint inside a synchronous run has already blown the 30-second cap nine and a half minutes ago.
A timeout is a failure like any other: it consumes an attempt and then follows onError.
Stop and Error
Stop and Error (revenexx:stop-and-error) fails the run on purpose, with a message and an optional error code. It always fails the run regardless of any onError setting, and its single output port is never emitted.
Use it to make a failure say something. Supplier feed had 0 articles — check the drop in the run's reason is worth more than a bare engine error, and it is what someone reading the run list at 09:00 sees first.
Where a failure shows up
| Where | What you see |
|---|---|
| The run's Details | How the run ended and the platform's own reason |
| The run's Timeline | Which step failed, how long it took, and its recorded input and output |
| The step detail | The stack trace, where the failure produced one |
| Missed runs | Firings that never became a run at all |
See Runs and Missed runs.
Where to go next
- Node configuration — where these settings sit in the inspector.
- Runs — reading the failure, and retrying or resuming.
- Node catalog — which nodes declare an
errorport. - Schedule triggers — why idempotent writes are not optional.