Skip to content
DevOps AI ToolKit
Newsletter
All guides
AI for Jenkins By James Joyner IV · · 9 min read

Jenkins Error: 'WorkflowScript: 1: unable to resolve class <ClassName>' — Cause, Fix, and Troubleshooting Guide

Quick answer

Fix 'WorkflowScript: 1: unable to resolve class <ClassName>' in Jenkins pipelines: shared library src/ layout, @Library, imports, and missing plugin classes.

  • #jenkins
  • #ci-cd
  • #troubleshooting
  • #errors
Free toolkit

Fixing errors like this? Get 500 free DevOps AI prompts

500 copy-paste AI prompts for the stack you actually run — one PDF, free.

Overview

A pipeline fails at compile time — before a single step runs — because Groovy cannot find a class your Jenkinsfile imports or references. The build log ends with a MultipleCompilationErrorsException whose first line reads:

org.codehaus.groovy.control.MultipleCompilationErrorsException: startup failed:
WorkflowScript: 1: unable to resolve class com.example.utils.Deployer
 @ line 1, column 1.
   import com.example.utils.Deployer
   ^
1 error

The class is either not on the pipeline classpath (a shared library isn’t loaded, or its src/ layout is wrong), or the plugin that supplies the class isn’t installed. Because this is a compilation failure, none of your stages execute — the whole run is aborted immediately.

Symptoms

  • The build fails instantly with WorkflowScript: N: unable to resolve class ... and a caret pointing at an import line.
  • Stages never start; the console output is only the compilation stack trace.
  • The pipeline worked on one controller/folder but fails on another after being copied.
  • It fails only after a shared library was renamed, moved, or its version pinned to a bad branch.
  • A @Grab or third-party import that works in plain Groovy fails inside Jenkinsfile.
  • Autocompletion in your editor is happy, but Jenkins rejects the same import.

Common Root Causes

  • Shared library not loaded — you reference a library class but never declared @Library('my-shared-lib') (or the library isn’t configured globally / at folder level).
  • Wrong src/ package layout — the class file isn’t at src/<package path>/ClassName.groovy matching its package declaration, so the library compiler can’t find it.
  • Missing plugin that provides the class — imports like com.cloudbees.plugins.credentials.* or hudson.model.* resolve only if the corresponding plugin is installed on the controller.
  • Typo or wrong package in the import — the class name or package path doesn’t match the actual file (case-sensitive).
  • Library configured but not trusted/loaded implicitly — “Load implicitly” is off and no @Library annotation was added, so src/ classes aren’t on the classpath.
  • Version/branch pin points at code that lacks the class@Library('my-shared-lib@feature-x') resolves to a branch where the class doesn’t exist yet.
  • Class lives in vars/ not src/ — global variables in vars/ are called as steps, not imported as classes; importing them fails.

How to diagnose

First read the caret in the stack trace — it names the exact unresolved class and the line. Confirm whether it’s a library class or a plugin class.

Check that the library is actually loaded by printing the effective libraries at the top of the run. In a scripted or declarative script {} block:

// Temporary diagnostic — remove after debugging
echo "Loaded libraries: ${env.LIBRARIES ?: 'none reported'}"
try {
  echo Class.forName('com.example.utils.Deployer').name
} catch (Throwable t) {
  echo "Cannot load class: ${t}"
}

Verify the shared library configuration in the UI:

  • Global library: Manage Jenkins → System → Global Trusted Pipeline Libraries.
  • Folder library: → Configure → Pipeline Libraries.

Confirm the file exists at the path the package requires. A class declared package com.example.utils must live at:

(repo root)/src/com/example/utils/Deployer.groovy

For a missing-plugin case, check installed plugins from the Script Console (Manage Jenkins → Script Console):

// Is the plugin that ships this class present?
Jenkins.instance.pluginManager.plugins
  .findAll { it.shortName.contains('credentials') }
  .each { println "${it.shortName} ${it.version}" }

You can also list the library retrieval on the controller filesystem:

# On the controller: libraries are cached per job build
ls -R "$JENKINS_HOME/jobs/<job>/builds/<n>/libs/" 2>/dev/null

Fixes

1. Declare and load the shared library

If the class comes from a shared library, annotate the import so Jenkins retrieves it. The @Library annotation must come before the import:

@Library('my-shared-lib') _
import com.example.utils.Deployer

pipeline {
  agent any
  stages {
    stage('Deploy') {
      steps {
        script {
          def d = new Deployer(this)
          d.run('staging')
        }
      }
    }
  }
}

The trailing _ is required — it’s the target of the annotation. Pin a version explicitly when you need reproducibility: @Library('my-shared-lib@v1.4.0') _.

2. Fix the src/ package layout

The directory structure under src/ must mirror the package declaration exactly (case-sensitive):

my-shared-lib/
├── src/
│   └── com/
│       └── example/
│           └── utils/
│               └── Deployer.groovy   // package com.example.utils
└── vars/
    └── deploy.groovy                 // called as a step: deploy()
// src/com/example/utils/Deployer.groovy
package com.example.utils

class Deployer implements Serializable {
  def script
  Deployer(script) { this.script = script }
  void run(String env) { script.sh "deploy.sh ${env}" }
}

3. Configure the library globally or at folder scope

For a global library, add it under Manage Jenkins → System → Global Trusted Pipeline Libraries: set the name, default version (branch/tag), and a Git retrieval source. Enable Load implicitly only if every job should get it without @Library. For a single team, prefer a folder-scoped library (Folder → Configure → Pipeline Libraries) so it’s isolated and doesn’t need controller-admin rights.

4. Install the plugin that provides the class

If the unresolved class is a plugin API (e.g. com.cloudbees.plugins.credentials.CredentialsProvider), install the plugin via Manage Jenkins → Plugins → Available, then restart if prompted. Do not try to @Grab plugin jars into the pipeline — use the plugin.

5. Don’t import vars/ globals

Code in vars/deploy.groovy is a global step, not an importable class. Call it directly instead of importing:

@Library('my-shared-lib') _
pipeline {
  agent any
  stages {
    stage('Deploy') { steps { deploy('staging') } }  // no import
  }
}

What to watch out for

  • Put @Library(...) _ at the very top of the file; annotations after the first statement are ignored and the class stays unresolved.
  • Keep src/ package paths and file names case-correct — Linux controllers are case-sensitive even if your laptop isn’t.
  • Pin library versions in production (@lib@tag); a floating master/main can silently drop a class when someone refactors.
  • Prefer trusted global libraries in vars/ over signature approvals when code needs privileged calls (see the Script Security guide below).
  • Restart the controller after installing a plugin that supplies imported classes; the class loader picks it up on restart.
  • For recurring pipeline failures across many jobs, the free incident assistant can triage the compile trace quickly.
Free download · 368-page PDF

Get 500 Battle-Tested DevOps AI Prompts — Free

500 battle-tested, copy-paste AI prompts engineered by a senior systems engineer — every one with fill-in placeholders and safety/back-out notes. Drop your email and it's yours.

  • 500 prompts: Linux · Kubernetes · Terraform · OpenStack · GitLab · Docker · Monitoring · Incident Response
  • Instant PDF download — yours free, forever
  • Plus one practical AI-workflow email a week (no spam)

Single opt-in · unsubscribe anytime · no spam.