Uploaded image for project: 'Jenkins'
  1. Jenkins
  2. JENKINS-34376

Cannot easily/safely catch exceptions without disrupting job abortion


    • Icon: Improvement Improvement
    • Resolution: Duplicate
    • Icon: Major Major
    • pipeline
    • None
    • Jenkins ver. 1.656, pipeline 2.0

      There doesn't seem to be a safe method of catching errors that might occur while running a shell command without disrupting the normal job stopping process. I would like to be able to catch the error (as it might just be a failing test), log it, and continue running the pipeline script. My main concern is being able to still allow stopping or aborting the pipeline. This would suggest to me that I need to allow exceptions to bubble up if it is due to an abort.

      Manually aborting (by pressing red stop button in the gui) will either raise an AbortException or a FlowInterruptedException depending on whether the pipeline is running a shell command or not. This makes it difficult to determine if the shell command failed or a job abort was requested. If a shell command is aborted, the AbortException will at least have a message about an exit code 143. (I think)

      To further confuse things, I am wrapping some shell scripts with a timeout step. Timeout also raises FlowInterruptedException but at least the exception will have ExceededTimeout as the cause.

      I thought maybe I could look at currentBuild.result but it seems to be always null. I looked at 'catchError' but that doesn't set the result to 'ABORTED' when stopping during a shell command. (It also seems to ignore when a user is trying to abort the job)

      Basically, to be able to recover from errors but also allow stopping pipelines, I think I have to use this monstrosity:

      onErrorMarkUnstable("sleep step") {
          // stopping here raises FlowInterruptedException
          sleep 10
      onErrorMarkUnstable("sleep shell") {
          node {
              // error here raises AbortException, stopping here raises AbortException
              // a script that fails.. we want to be able to log that it failed and continue testing.
              sh "sleep 10 && false"
      onErrorMarkUnstable("sleep shell with timeout") {
          // we want to log that it timed out and continue.
          timeout (time: 5, unit: 'SECONDS')  {
              node {
                  // error here raises AbortException, stopping here raises AbortException, timeout raises FlowInterruptedException
                  sh "sleep 10 && false"
      echo "last line, done!"
      def onErrorMarkUnstable(desc, Closure body) {
          echo "${desc}"
          try {
          } catch (org.jenkinsci.plugins.workflow.steps.FlowInterruptedException e) {
              def allowInterruption = true;
              for (int i = 0; i < e.causes.size(); i++) {
                  // white list ExceededTimeout
                  if (e.causes[0] instanceof org.jenkinsci.plugins.workflow.steps.TimeoutStepExecution.ExceededTimeout) {
                      echo "${desc}: An error occured (${e.causes[0]}) marking build as failed."
                      currentBuild.result = "UNSTABLE"
                      allowInterruption = false;
              if (allowInterruption) { throw e; }
          catch (hudson.AbortException e) {
              def m = e.message =~ /(?i)script returned exit code (\d+)/
              if (m) {
                  def exitcode = m.group(1).toInteger()
                  if (exitcode >= 128) {
                      throw e;    //  killed because of abort, letting through
              echo "${desc}: An error occured (${e}) marking build as failed."
              currentBuild.result = "UNSTABLE"

            jglick Jesse Glick
            sonneveldsmartward Nick Sonneveld
            4 Vote for this issue
            18 Start watching this issue