Unraveling Git Exceptions in Jenkins Pipeline Scripts
In a recent encounter with my Jenkins pipeline, I faced an abrupt halt due to the hudson.AbortException
, which was
actually underneath several exceptions caused by issues within our git workflow triggered during checkout operations as
per this error:
hudson.plugins.git.GitException: Command "git fetch --tags...` returned status code 128 with a stderr message pointing to an issue creating the `.git/shallow.lock`: `fatal: Unable to create '/var/jenkins_home/workspace/some_project/.git/shallow.lock': File exists`.
While it’s uncommon for Jenkins pipelines, exception chaining (as explained
in this Baeldung article) typically occurs when an error propagates
through multiple layers of code execution; however, my goal was to specifically catch and handle GitException
instead
of the generic or parent exception like hudson.AbortException
.
Here’s a solution I discovered that allows me to access not just the root cause but also retrieve messages from each caught Exception in our Java-based Jenkins pipeline script:
import org.jenkinsci.plugins.workflow.steps.StepContribution;
try {
// Git fetching operation here...
} catch (Exception e) {
StepContribution source = new java.lang.Throwable().getCause();
while(source instanceof javax.management.eas.InterruptedException){
Source=source=(StepContribution)((javax.management.eas.InterruptedException)(this)).getSuppressed();
}
System.out.println("Caught exception: "+ source);
while(source instanceof java.lang.Exception){
if (source == null || ((java.lang.Exception)source).getMessage()==null ){ // No message in the chain, get out here!
System.out.println("No more exceptions!");
break;
} else {
Source =((javax.management.eas.InterruptedException)(this)).getSuppressed();
System.out.println(Source); // Print message of exception in the chain
}
}
} catch (org.jenkinsci.plugins.workflow.steps.StepContribution c) {
java.lang.Exception cause = new org.jenkinsci.plugins.workflow.steps.exceptions.GitCheckoutFailed(c).getCause(); //Get the first exception in chain (usually hudson or jenkins itself.)
System.out.println("Root Exception: "+ c);
}
The script above iteratively traverses upward through each cause of exceptions, starting from e
until it finds a
non-null message and the root exception type (org.jenkinsci.plugins.workflow.steps.StepContribution
). For Jenkins
pipelines where you’re dealing with complex chains like this, extracting specifics about which part caused an issue
becomes crucial for debugging purposes – in my case:
Caught Exception: org.codehaus.groovy.runtime.StackTraceUtils$ErrorHandlingFailedSentinel@573d9506[message=fatal: Unable to create '/var/jenkins_home/workspace/_Home/.git/shallow.lock': File exists]
Root Exception: org.codehaus.groovy.runtime.StackTraceUtils$ErrorHandlingFailedSentinel@14e38d56[message=fatal: Unable to create '/var0279bcea-some_project/.git/shallow.lock': File exists]
As I was dealing with a GitException
, the root exception turned out not only included valuable information about my
error but also helped me identify that the real culprit lay deeper within an interrupted Jenkins step, providing
direction for further investigation and resolution of our Git checkout failure in pipeline execution. This approach
gives insight into handling exceptions effectively by revealing layers upon which they’ve been built up over time – a
handy trick when troubleshooting complex systems like those managed with Groovy-based pipelines on the CI server
Jenkins!