Troubleshooting Failed Builds Quickly Using the Jenkins CLI
Use the Jenkins CLI to inspect failed builds, stream logs, check parameters, and rerun jobs without digging through the UI.
Troubleshooting Failed Builds Quickly Using the Jenkins CLI
The Jenkins web UI is useful when you are exploring. The Jenkins CLI is better when you already know the job name, need the log now, or want to repeat the same checks without clicking through pages.
A failed build usually needs three pieces of information: what ran, where it failed, and what changed since the last good run. The CLI can pull all three quickly if you set it up once.
Set up a repeatable CLI command
Download the CLI jar from your own Jenkins controller:
curl -O "$JENKINS_URL/jnlpJars/jenkins-cli.jar"
Use an API token, not your account password:
export JENKINS_URL="https://jenkins.example.com"
export JENKINS_USER="your-user"
export JENKINS_API_TOKEN="your-api-token"
alias jcli='java -jar jenkins-cli.jar -s "$JENKINS_URL" -auth "$JENKINS_USER:$JENKINS_API_TOKEN"'
Test authentication before troubleshooting a real failure:
jcli who-am-i
jcli help
If this fails, fix CLI access first. Common causes are a wrong URL, a token copied with an extra space, missing permissions, or a Jenkins security setting that disables the CLI transport you are trying to use.
For shared scripts, avoid shell aliases. Wrap the command in a small script or use environment variables in your CI secret store so tokens do not end up in shell history.
Find the failed build
If you know the job name and build number, skip straight to the console log. If you only know that something failed recently, start with Groovy through the CLI:
jcli groovy = <<'EOF'
Jenkins.instance.getAllItems(hudson.model.Job.class).each { job ->
def b = job.getLastBuild()
if (b != null && b.result == hudson.model.Result.FAILURE) {
println "${job.fullName} #${b.number} ${b.getTime()}"
}
}
EOF
For folders and multibranch pipelines, use the full job name exactly as Jenkins knows it. A branch job might look like:
team-service/main
team-service/PR-42
folder-a/folder-b/deploy-prod
If a name contains spaces, quote it in your shell:
jcli console "Folder With Spaces/My Pipeline" 128
Pull the console log first
The console log is still the fastest source of truth for most failures:
jcli console MyPipelineJob 123
For long logs, save a copy and search with context:
jcli console MyPipelineJob 123 > build-123.log
grep -niE "error|failed|exception|traceback|permission denied|timeout" build-123.log | head -40
grep -niC 3 "permission denied" build-123.log
Do not rely only on the first line that contains "error". Build tools often print warnings, test names, or expected failure text. Look for the first meaningful failure after the stage starts, then read the lines before it. The cause is often above the stack trace.
For a running build, follow the log:
jcli console MyPipelineJob 123 -f
Some Jenkins versions and CLI modes accept --follow; others use -f. Check jcli help console on your controller.
Identify the stage that failed
Pipeline logs include stage markers. Search for them near the failure:
grep -n "\[Pipeline\] stage" build-123.log
Then inspect the section after the last stage marker before the error. If the log is noisy, open it with less:
less build-123.log
Inside less, search for /ERROR, /Exception, or /[Pipeline] stage.
A good Jenkinsfile makes this easier by printing clear step names before risky operations:
echo 'Installing npm dependencies'
sh 'npm ci'
echo 'Running unit tests'
sh 'npm test'
If every step is just sh './ci.sh', the CLI can still fetch the log, but the log may not tell you enough. In that case, improve the pipeline after the incident.
Check parameters and causes
A build can fail because it ran with the wrong branch, wrong environment, or stale parameter. Pull the build metadata with Groovy:
jcli groovy = <<'EOF'
def job = Jenkins.instance.getItemByFullName('MyPipelineJob')
def build = job?.getBuildByNumber(123)
if (build == null) {
println 'Build not found'
return
}
println "Job: ${job.fullName}"
println "Build: #${build.number}"
println "Result: ${build.result}"
println "Duration: ${build.durationString}"
println 'Causes:'
build.getCauses().each { println "- ${it.shortDescription}" }
println 'Parameters:'
build.getAction(hudson.model.ParametersAction)?.parameters?.each {
println "- ${it.name}=${it.value}"
}
EOF
This is especially helpful for deployment jobs. A failed production deployment with BRANCH=feature/test is a very different problem from a failed deployment of the expected release tag.
Be careful printing environment variables. They may include secrets. If you need environment details, print specific safe keys instead of dumping everything:
jcli groovy = <<'EOF'
def job = Jenkins.instance.getItemByFullName('MyPipelineJob')
def build = job?.getBuildByNumber(123)
def env = build?.getEnvironment(TaskListener.NULL)
['JOB_NAME', 'BUILD_NUMBER', 'BRANCH_NAME', 'GIT_COMMIT', 'NODE_NAME'].each { key ->
println "${key}=${env?.get(key)}"
}
EOF
If your script lacks permission or a plugin changes the available metadata, fall back to the console log and the job configuration.
Compare with the last successful build
A single failed log is useful. A failed log next to the last successful log is better.
Find the last successful build number:
jcli groovy = <<'EOF'
def job = Jenkins.instance.getItemByFullName('MyPipelineJob')
def b = job?.getLastSuccessfulBuild()
println b == null ? 'No successful build found' : b.number
EOF
Then fetch both logs:
jcli console MyPipelineJob 122 > build-122-success.log
jcli console MyPipelineJob 123 > build-123-failed.log
Compare the commands, dependency versions, agent labels, branches, and checkout SHAs. Many failures come from a changed base image, a moved dependency, a different agent, or a credential that expired between builds.
For Git-based pipelines, these values are often enough to start:
grep -nE "Checking out|GIT_COMMIT|BRANCH_NAME|git rev-parse|Docker|image:" build-123-failed.log
Rerun a build carefully
Once you understand the failure or have applied a fix, trigger a new build:
jcli build MyPipelineJob
For parameterized jobs:
jcli build MyPipelineJob -p BRANCH=main -p ENVIRONMENT=staging
To wait and stream output, check your controller's supported options:
jcli help build
Common options include waiting for completion and printing console output, but names can vary by Jenkins version and plugins.
Do not rerun production deployment jobs just to see what happens. Confirm parameters, credentials, and target environment first. If the job is not idempotent, a rerun can make the incident worse.
Use CLI output in incident notes
The CLI is good for leaving a trail. Save the exact log and the metadata you used:
mkdir -p incident-jenkins-123
jcli console MyPipelineJob 123 > incident-jenkins-123/console.log
jcli get-job MyPipelineJob > incident-jenkins-123/job-config.xml
Treat job-config.xml as sensitive if it contains credentials references, URLs, or internal names. Do not paste it into public tickets.
A compact incident note might include:
Job: MyPipelineJob #123
Failed stage: Unit tests
First failing command: npm test
Commit: abc1234
Agent: linux-build-07
Likely cause: dependency install used Node 22 instead of expected Node 20
Action: pinned tool version and reran #124 successfully
That is far more useful than "Jenkins failed."
A practical troubleshooting flow
Use this order when a build fails and you need signal fast:
jcli who-am-i
jcli console MyPipelineJob 123 > build-123.log
grep -niE "error|failed|exception|permission denied|timeout" build-123.log | head -40
grep -n "\[Pipeline\] stage" build-123.log
Then inspect parameters and causes with Groovy, compare with the last successful build, and rerun only after you know whether the failure was code, infrastructure, credentials, or input parameters.
The Jenkins CLI will not magically diagnose every failed build. What it does well is remove friction. It gets the log, metadata, and rerun command into your terminal quickly, where you can search, diff, save, and repeat the same checks the next time a pipeline breaks.