Jenkins Error Handling

Pipelines fail. Networks drop, servers restart, and tests flake. A well-built pipeline expects trouble and reacts with a plan: retry, wait, clean up, or alert. Error handling separates a fragile script from a dependable delivery system.

The Layman's View

Consider a delivery driver. If a road is closed, a good driver tries another route, waits a few minutes when traffic clears, and phones the customer when the package will arrive late. A poor driver turns around and goes home. Jenkins error handling gives your pipeline the habits of the good driver.

Build Results in Jenkins

ResultColourMeaning
SUCCESSBlue or greenEvery step passed
UNSTABLEYellowThe build finished but tests failed or quality checks warned
FAILURERedA step failed and stopped the run
ABORTEDGreyA person or a timeout stopped the run

The Error Handling Toolbox

              step runs
                  |
        +---------+----------+
        |                    |
     passes                fails
        |                    |
        |        +-----------+-----------+
        |        |           |           |
        |      retry      catchError   try/catch
        |    (try again)  (mark & go)  (custom reaction)
        |
   post block runs in every case: always, success, failure, unstable, cleanup

The retry Step

Retry repeats a block when it fails. Use it for flaky actions such as downloads and remote calls.

stage('Download') {
    steps {
        retry(3) {
            sh 'curl -fO https://example.com/data.zip'
        }
    }
}

Jenkins runs the command up to three times. The stage fails only when all three attempts fail.

The timeout Step

A hung process can hold an agent for hours. Timeout stops it after a set time.

timeout(time: 10, unit: 'MINUTES') {
    sh './long-running-task.sh'
}

Combine timeout with retry to attempt a slow action twice, each limited to five minutes.

retry(2) {
    timeout(time: 5, unit: 'MINUTES') {
        sh './sync.sh'
    }
}

try and catch

Scripted code and script blocks accept Groovy try, catch, and finally. This pattern lets you run custom actions when a step fails.

steps {
    script {
        try {
            sh './risky-step.sh'
        } catch (err) {
            echo "Step failed: ${err.getMessage()}"
            currentBuild.result = 'UNSTABLE'
        } finally {
            echo 'Cleaning temporary files'
        }
    }
}

The catch block swallows the error, so the pipeline keeps running. Setting the result to UNSTABLE records that something went wrong.

The catchError Step

CatchError offers a simpler path in declarative pipelines. It lets you choose both the build result and the stage result.

stage('Optional Lint') {
    steps {
        catchError(buildResult: 'UNSTABLE', stageResult: 'FAILURE') {
            sh './lint.sh'
        }
    }
}

The stage shows red, the build shows yellow, and later stages still run. This fits checks that inform the team but should not block a release.

The post Section

The post block runs after stages finish. It handles cleanup and alerts in every outcome.

post {
    always   { junit 'target/surefire-reports/*.xml' }
    success  { echo 'Build passed' }
    failure  { mail to: 'team@example.com',
                    subject: "Failed: ${env.JOB_NAME}",
                    body: "See ${env.BUILD_URL}" }
    unstable { echo 'Some tests failed' }
    cleanup  { deleteDir() }
}

Post Conditions

ConditionRuns When
alwaysEvery time
successThe build succeeds
failureThe build fails
unstableThe build turns unstable
changedThe result differs from the last build
cleanupAfter every other post condition

Choosing the Right Tool

  • Use retry for temporary problems that often fix themselves.
  • Use timeout for steps that may hang.
  • Use catchError for non-critical checks.
  • Use try and catch when you need custom logic.
  • Use post for cleanup and alerts.

Mistakes to Avoid

Retrying Everything

Retry hides real bugs. A test that fails randomly needs a fix, not endless repetition.

Swallowing Errors Silently

A catch block with no message and no result change leaves the team blind. Always log the error or set a result.

Skipping Cleanup

Leftover containers and temporary files pile up on agents. Place cleanup in post, which runs after failures too.

A Simple Policy for Your Team

Write down which failures stop a release and which failures only raise a warning. Unit test failures and build errors usually block a release. Style checks and optional reports usually warn. Encode that policy with catchError and the unstable result, so the pipeline enforces it without debate. Review the policy every quarter, since a warning that nobody reads turns into noise. Teams that agree on these rules early spend far less time arguing over red and yellow builds later.