Error Handling v2

The Runtime records a failing Step in Workflow Logs and stops normal execution unless an enclosing Try/Catch handles the exception.

Try, Catch, and Finally

A Try/Catch container has structural sections named exactly Try, Catch, and Finally:

  • Try contains the work that can fail.
  • Catch runs only when a Step in Try raises an exception.
  • Finally runs after normal Try completion or after Catch handles an exception.

When a Step fails, the Runtime abandons the remaining work in that Try section, closes its deferred-consumer scope, and starts the nearest Catch section. If a Step in Catch or Finally fails, the new exception can propagate to an enclosing Try/Catch or fail the Workflow.

You can map Returns from Steps in Try or Catch into Steps in Finally within the same TryCatch. Do not map directly between Try and Catch. A permitted mapping does not guarantee that its source Step ran: Catch is skipped on success, and a failure can skip later Steps in Try.

Error details

Keep the Try/Catch container's generated Error Return when the Catch section needs failure details. It contains:

Field Meaning
Message Exception message captured by the Runtime. Messages longer than 10 KiB are truncated and end with ....
At Authored name of the Step where the exception occurred.

Reference these fields inside Catch through the owning Step, for example, {handleError.Error.Message} and {handleError.Error.At}.

Treat error messages as diagnostic text rather than a stable machine-readable contract. A Node or dependency can change its wording, and a message can contain sensitive data. Avoid returning it directly to an unauthorised caller or copying it into an unredacted Property.

Unhandled errors

Without a matching handler, the Runtime reports an unhandled error at the failing Step and the Workflow activation fails. Inspect the failing Step's Parameter and Return logs, error details, and preceding Steps to diagnose it.

An error from a Sub-Workflow propagates through its parent call Step, so an enclosing parent Try/Catch can handle it. The child and parent logs remain separate but linked by the nested invocation context.

Validation and compilation diagnostics happen before execution and cannot be caught by a Workflow Try/Catch. Runtime Stop and execution-timeout cancellation also bypass the Catch branch so cancellation can end the activation.

Design guidance

Use Try/Catch around a boundary where you can make a meaningful decision, such as recording a failed delivery, selecting a controlled fallback, or returning an approved error response. Avoid wrapping a complete Workflow only to suppress every failure.

Use Finally for cleanup or completion work that must run on both the success and handled-error paths. Keep that work safe to run when the Try section produced no result.

Use Finally for follow-up work

For example, suppose a Step named recordFailure in Catch returns a String named Message. A Step in Finally can use that message when error handling ran, and a fallback when Catch was skipped:

{recordFailure.Message} ?? "No failure was recorded."

A String Return with no stored result resolves to null, which allows this fallback. This example assumes recordFailure belongs to the same TryCatch and that its Return is a String; do not treat a missing result as a success indicator or assume every data type accepts null. Give mandatory cleanup work the information it needs on both paths, and test the success and handled-error paths.

Record-level failures

A Node can complete normally while returning unsuccessful records. For Methods that expose normalized Flowgear metadata, inspect Flowgear.IsSuccess on each result. Flowgear.Message describes that record's outcome, and Flowgear.Request, when provided, identifies the input that produced it. These fields belong to the Node's response contract; they are not present on every Node or Method.

For example, the FreshBooks Create, Update, and Delete Methods return mutation results with this metadata. A batch can contain both successful and failed records without raising an exception for each failed record. A Try/Catch alone therefore does not establish that every write succeeded.

Consume the results, separate successful and failed records, and preserve enough correlation information to investigate or retry a failure. Keep Try/Catch for exceptions that still prevent the operation or its deferred results from completing. See Handle Partial Batch Failures for a worked example.

See also

See Container Steps and Scope, Workflow Log Redaction, and Activation Modes and Timeouts.