engine object in the node’s config; the plugin never sees it. Why the engine owns failure is in the failure model.
Steps
1
Route what fails to a dead-letter node
onError says what happens to a message that still fails: FAIL (default) fails the node, CONTINUE drops the message, ROUTE sends it, with its failure attached, to the node’s error port. Save as failures.json. A ticket whose kind is not bug matches no case, so the strict BRANCH fails it:failures.json
sourcePort never carries a dead letter: the edge must say "sourcePort": "error", or the failure is dropped.2
Retry the transient
retry runs the plugin again for the failing message with exponential backoff and jitter: maxAttempts (total, 1 to 10, default 3), backoffMs (default 200, doubling) and maxBackoffMs (default 10000). Narrow it with retryOn or noRetryOn (exception class names). Bad input (IllegalArgumentException) is never retried unless listed. A message produces all of its output or none: output emitted before a failed attempt is dropped.3
Cap the damage with a failure budget
ROUTE and CONTINUE can hide an outage: if a service is down, every message goes quietly to the dead letter. A budget makes the node fail instead once more than maxFailures messages fail within windowMs:onError set to ROUTE or CONTINUE; with FAIL the node is refused at validation.4
Decide what a failed branch means at a join
A node with several parents starts by
engine.trigger: ALL_SUCCESS (default) fails when one parent fails, ALL_DONE carries on with the parents that worked, ONE_SUCCESS carries on but fails when every parent failed. This is how to send a report even if one optional check failed.5
Bound time too
A step that hangs is a failure.
elementTimeoutMs limits one message (and counts as a failure, so retry and onError apply), deadlineMs limits the node’s whole run. See Time limits.Verify it worked
RESULT event comes from dead-letter, and the message carries failure.attempts (2), failure.exception and failure.message; the run still ends SUCCESS. With "kind":"bug" it comes from bugs. Change onError to FAIL and the same ticket fails the node (FAILURE) and ends the run: that run is what the supervisor guide replays (Replay a supervisor).
Variations
- A run can end
SUCCESSwith a failed branch inside it. Look at node statuses (Status values), not only the run status. - Make side effects idempotent. A retried or resumed step can see a message twice (Delivery and back-pressure).
- Do not retry AI calls blindly. Prefer a gate after the model, or a fallback model (AI and deterministic work).
Related
- Node options reference for every
enginekey. - Messages reference for the
failure.*labels. - Loop and retry for repeating work that has not failed.