Plan errors and failure

Any plan that completes execution without an error is considered successful. There are some specific scenarios that always cause a plan failure, such as calling the fail_plan function.

Plan failure due to absent catch_errors option

If you call some functions without the _catch_errors option and they fail on any target, the plan itself fails. These functions include:

  • upload_file
  • run_command
  • run_script
  • run_task
  • run_plan

If there is a plan failure due to an absent _catch_errors option when using run_plan, any calling plans also halt until a run_plan call with _catch_errors or a catch_errors block is reached.

Failing a plan

If you are writing a plan and think it's failing, you can fail the plan with the fail_plan function. This function fails the plan and prevents calling plans from executing any further, unless run_plan was called with _catch_errors or in a catch_errors block.

For example, use the fail_plan function to pass an existing error or create a new error with a message that includes the kind, details, or issue code.

fail_plan('The plan is failing', 'mymodules/pear-shaped', {'failednodes' => $result.error_set.names})
# or
fail_plan($errorobject)

Catching errors in plans

When you use the catch_errors function, it executes a block of code and returns any errors, or returns the result of the block if no errors are raised.

Here is an example of the catch_errors function.

plan test (String[1] $role) {
  $result_or_error = catch_errors(['pe/puppetdb-error']) || {
    puppetdb_query("inventory[certname] { app_role == ${role} }")
  }
  $targets = if $result_or_error =~ Error {
    # If the PuppetDB query fails
    warning("Could not fetch from puppet. Using defaults instead")
    # TargetSpec string
    "all"
  } else {
    $result_or_error
  }
}

If there is an error in a plan, it returns the Error data type, which includes:

  • msg: The error message string.
  • kind: A string that defines the kind of error similar to an error class.
  • details: A hash with details about the error from a task or from information about the state of a plan when it fails, for example, exit_code or stack_trace.
  • issue_code: A unique code for the message that can be used for translation.

Use the Error data type in a case expression to match against different kinds of errors. To recover from certain errors and fail on others, set up your plan to include conditionals based on errors that occur while your plan runs. For example, you can set up a plan to retry a task when a timeout error occurs, but fail when there is an authentication error.

The first plan below continues whether it succeeds or fails with a mymodule/not-serious error. Other errors cause the plan to fail.

plan mymodule::handle_errors {
  $result = run_plan('mymodule::myplan', '_catch_errors' => true)
  case $result {
    Error['mymodule/not-serious'] : {
      notice("${result.message}")
    }
    Error : { fail_plan($result) } }
  run_plan('mymodule::plan2')
}