Skip to content

CATCH statement

Runs the ops nested underneath it when the block above it failed, and does nothing when that block succeeded. It is the second half of a pair: it only works directly after a TRY statement (needs a catch), described in TRY statement. The palette lists it as CATCH statement (needs a try_with_catch).

The op has no configuration of its own. Its Config tab holds the op's Name and an empty data editor. What you get instead is the failure text, handed to you in the stash under _last_error.

the TRY block did it fail? no yes CATCH is skipped entirely CATCH runs its nested ops, with _last_error

What you get in the stash

Before the nested ops run, the failure text is written into the stash as _last_error. Read it anywhere a stash variable is accepted, as ${_last_error} in a message field or as the bare name _last_error in a condition row.

The text is whatever the failing op threw. For a FAIL it is the message you wrote, after variable expansion. When the failure came from a job op rather than a control statement, that message is wrapped before it reaches you: the text starts with Error running task, then the failing op's name between asterisks, then a colon, then the original wording. Errors raised by Clarive itself also end in a newline. Both are reasons to match _last_error with LIKE in IF var condition THEN rather than comparing it for equality.

_last_error is never cleared. It stays in the stash for the rest of the job and carries into the following job steps, so a test that reads it much later can be looking at an error from an earlier step. Read it inside the CATCH block, copy what you need into a variable of your own, or remove it with DELETE hashkey once you are done with it.

What the block does and does not do

CATCH does not re-raise. Once it finishes, the rule carries on with the next op after it, the job status is unaffected, and the job does not switch to its rollback pass on account of that failure. To end the run anyway, put a FAIL inside the CATCH.

An error raised inside the CATCH block is not caught by the same TRY. It escapes to whatever handling surrounds the pair, or ends the rule.

The CATCH op does not show up as a step of its own in the job log. The ops nested inside it do, so give those clear names. It is not a cancellation checkpoint either.

A rollback mark set by an op inside the failed TRY block stays set. Handling the error here does not clear it, so a later failure elsewhere in the job still rolls that op back. See rollback.

Placement rules

The CATCH must be the very next op after a TRY statement (needs a catch), at the same level in the tree. Nothing may sit between them.

A CATCH that follows a TRY statement (without catch), or that sits on its own, stops the rule at run time with a complaint about a useless bare catch. The designer does not warn you when you save.

One TRY takes exactly one CATCH. Drop a second CATCH after the first and the first one still runs to completion; the rule then dies on the second with the same useless-bare-catch complaint, leaving you with a half-handled error and a failed rule.

Clearing Enabled on the TRY removes the whole TRY block from the rule, nested ops included, and leaves the CATCH with nothing in front of it. Disable the pair together or leave both alone.

Leave the Options tab at its defaults apart from Enabled. The Name field on the Config tab and the Note tab are safe too. Error Handling, Parallel Mode, Run Forward, Run Rollback, Needs Rollback?, Semaphore Key, Sub Name, Stage Name, a Timeout above zero and a Debug Mode of Op Trace + Stash Dump each wrap extra work around the op, which pushes the CATCH out of reach of the TRY. Put those settings on the ops nested inside instead. The options themselves are covered in Rule Palette.

Combining with other ops

LOG Message inside the CATCH is the minimum worth doing. Without it, the only trace of the failure is whatever the failing op logged on its way out.

SET VAR inside the CATCH records that something went wrong, so a later IF var condition THEN can change what the rest of the rule does.

FAIL inside the CATCH replaces a machine-generated error with wording the person reading the job can act on.

Examples

Record the failure and keep going, so the rest of the step still runs.

TRY statement (needs a catch)
  Run a remote script         build script on myapp
CATCH statement
  LOG Message                 Build step failed: ${_last_error}
  SET VAR                     build_failed = 1

Branch on the kind of failure, using a pattern match against the captured text.

TRY statement (needs a catch)
  Web Request                 GET the bar service status
CATCH statement
  IF var condition THEN
    When: Any
      _last_error   LIKE   timed out        (Ignore case)
    LOG Message               Bar service is slow, carrying on without it
  ELSE
    FAIL                      Bar service call failed: ${_last_error}