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

Jenkins Error: 'groovy.lang.MissingPropertyException: No such property: <name> for class: WorkflowScript' — Cause, Fix, and Troubleshooting Guide

Quick answer

Fix Jenkins 'groovy.lang.MissingPropertyException: No such property for class: WorkflowScript': resolve undefined vars, scope, params vs env, and imports.

  • #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

Your Jenkinsfile referenced a variable that Groovy cannot resolve at that point in the script. WorkflowScript is the class Jenkins compiles your Pipeline into, so “No such property … for class: WorkflowScript” means: at the top level of your pipeline, there is no binding, no def, no parameter, and no environment entry with that name in scope.

groovy.lang.MissingPropertyException: No such property: IMAGE_TAG for class: WorkflowScript
	at org.codehaus.groovy.runtime.ScriptBytecodeAdapter.unwrap(ScriptBytecodeAdapter.java:...)
	at WorkflowScript.run(WorkflowScript:23)

The class name after “for class:” tells you where the lookup happened — WorkflowScript is your Jenkinsfile, a shared-library class name points into src/, and a step name points inside that step’s closure. Almost always this is a typo, a scoping mistake (a def that is not visible where you use it), confusion between params/env/global variables, or a variable used before it was assigned.

Symptoms

  • The pipeline fails at compile/run time with MissingPropertyException: No such property: <name> for class: WorkflowScript.
  • It fails on a specific line that references a bare identifier (e.g. echo IMAGE_TAG rather than echo env.IMAGE_TAG).
  • A variable set inside one block is “undefined” when read in another block or stage.
  • The value exists as a build parameter or environment variable, but you referenced it by the wrong accessor.
  • The error appears only after a rename, a copy-paste between Jenkinsfiles, or moving code into a shared library.

Common Root Causes

  • Typo or wrong caseimageTag vs IMAGE_TAG vs image_tag; Groovy property lookup is exact and case-sensitive.
  • Out-of-scope def — a variable declared with def inside a closure/stage is local to that block and is not visible elsewhere; reading it later throws.
  • Using a variable before assignment — the reference executes on a path where the variable was never set (e.g. only assigned inside an if).
  • params vs env vs global confusion — a build parameter is params.NAME, an environment variable is env.NAME; referencing a bare NAME at top level only works if a global/binding of that exact name exists.
  • Missing shared-library import — a global variable or class provided by a shared library is referenced without @Library importing it, so the name is unbound.
  • Relying on def for a cross-stage variable in declarative — declarative pipelines evaluate environment {} and stages differently; a top-level def may not be visible where you expect.

How to diagnose

Read the property name and the class. for class: WorkflowScript means the Jenkinsfile top level; a different class name points into a shared library. Then check how the value is actually supposed to be supplied.

Confirm what parameters and environment the build actually has. Add a temporary debug step:

// Temporary: what is actually in scope?
echo "params: ${params}"                 // all build parameters
echo "env keys: ${env.getEnvironment().keySet()}"  // env variable names

For declarative pipelines, dump the environment from a shell step to see exactly what is exported:

steps {
  sh 'printenv | sort'   // shows env.* exported to the shell
}

Use Replay (in the build’s left menu) to edit the Jenkinsfile inline and re-run quickly while you locate the bad reference. Grep the repo for the name to catch a declaration/scope mismatch:

# Where is the name defined vs used?
grep -RnE '\bIMAGE_TAG\b' Jenkinsfile vars/ src/

Fixes

1. Reference parameters and environment with the right accessor

A build parameter is on params; an environment variable is on env. Do not reference them as bare identifiers.

pipeline {
  agent any
  parameters {
    string(name: 'IMAGE_TAG', defaultValue: 'latest', description: 'Image tag to deploy')
  }
  stages {
    stage('Deploy') {
      steps {
        // WRONG: echo IMAGE_TAG  -> No such property: IMAGE_TAG
        echo "Deploying ${params.IMAGE_TAG}"   // build parameter
        echo "Build URL: ${env.BUILD_URL}"     // environment variable
      }
    }
  }
}

2. Declare cross-stage variables at the right scope

In a scripted pipeline, declare the variable at node/script scope (not inside the block that first sets it) so later stages can read it. In declarative, set it into env or use a script-level variable:

// Scripted: declare once at the top so every stage sees it
node {
  def imageTag        // visible to the whole node block
  stage('Build') {
    imageTag = sh(script: 'git rev-parse --short HEAD', returnStdout: true).trim()
  }
  stage('Deploy') {
    sh "deploy --tag ${imageTag}"   // in scope here
  }
}

For declarative pipelines, promote the value into env so it survives across stages:

pipeline {
  agent any
  stages {
    stage('Build') {
      steps {
        script { env.IMAGE_TAG = sh(script: 'git rev-parse --short HEAD', returnStdout: true).trim() }
      }
    }
    stage('Deploy') {
      steps { sh 'deploy --tag "$IMAGE_TAG"' }   // env.IMAGE_TAG is exported
    }
  }
}

3. Guard against use-before-assignment

If a variable is only set on some paths, give it a default so a read never hits an unbound name:

def artifact = ''    // default so it is always defined
if (fileExists('target/app.jar')) {
  artifact = 'target/app.jar'
}
echo "artifact: ${artifact ?: 'none built'}"

4. Import the shared library that defines the name

If the missing property is a shared-library global variable (a file under vars/) or class, import the library so the binding exists:

@Library('my-shared-lib@main') _   // the trailing _ imports global vars

pipeline {
  agent any
  stages {
    stage('Notify') {
      steps { notifySlack('build ok') }   // vars/notifySlack.groovy
    }
  }
}

Confirm the library is registered under Manage Jenkins → System → Global Pipeline Libraries with the exact name you referenced.

5. Fix the typo

The dull-but-common answer: the name is misspelled or mis-cased. Groovy will not fuzzy-match. Compare the reference to the declaration character for character — IMAGE_TAG and Image_Tag are different properties.

What to watch out for

  • The name after No such property: is exactly what Groovy looked up — search for that literal string; do not assume it is the variable you think you used.
  • Bare identifiers only resolve to Pipeline global variables or script bindings. For parameters use params.X, for environment use env.X (or $X inside a sh string).
  • A def inside a stage/closure is local to that block. If two stages need it, declare it at node/script scope or store it in env.
  • env.X values are always strings — assigning a number or boolean gets coerced; compare accordingly.
  • After adding a shared-library global, remember the @Library(...) _ line (with the underscore) or the global stays unbound.
  • The free incident assistant can point at the offending line from a pasted stack trace.
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.