Stage-level environment variable missing in later Declarative Pipeline stages
0 reputation · 30 Dec 2023, 02:05 UTC
0 reputation · 30 Dec 2023, 02:05 UTC
Determine whether a variable defined in a stage‑level environment block of a Jenkins Declarative Pipeline is automatically available to stages that follow it.
The inheritance of stage‑level environment settings is not explicitly documented and appears to differ between Jenkins core releases, Pipeline plugin versions, and when plugins such as EnvInject or Config File Provider are present; additionally, the behavior may change when stages execute on different agents in a distributed build.
Does a stage‑level environment block propagate its variables to subsequent stages in the same pipeline run? Is the propagation consistent across Jenkins core 2.400+ and Pipeline plugin 2.12+? Are there known plugin interactions that suppress or alter this inheritance?
34775 reputation · 30 Dec 2023, 05:02 UTC
No. A variable defined in a stage-level environment block in a Jenkins Declarative Pipeline is scoped to that stage only. It is not automatically available to stages that follow it in the same run. Only the top-level (pipeline-level) environment block is inherited by every stage.
The confirmed, well-established behavior is the scoping rule itself: stage-level environment applies to the steps inside that stage; pipeline-level environment applies everywhere. This has been stable across Jenkins LTS lines and Pipeline plugin versions, including the 2.400+ core / 2.12+ plugin ranges mentioned in the question.
The likely explanation for the apparent inconsistency you describe is one of three things:
env.* mutation. Assigning env.MY_VAR = 'x' inside a script block writes to the global environment map for the run, which does persist to later stages on the same node. This is a different mechanism from declarative environment scoping and is a common source of "it worked before" surprises.If later stages need the value, pick one of these:
environment block if it is static for the whole run.script step and assign env.MY_VAR = ..., accepting that this is imperative and can behave unexpectedly with parallel stages or agent changes.env.* at all — pass the value via stash/unstash, an archived artifact, or re-compute it per stage. Environment mutations do not reliably cross node boundaries.A minimal reproduction settles the question for your exact Jenkins and plugin versions:
pipeline {
agent any
stages {
stage('one') {
environment { FOO = 'bar' }
steps { echo "stage one: ${env.FOO}" }
}
stage('two') {
steps { echo "stage two: ${env.FOO}" } // prints null
}
}
}Then move environment { FOO = 'bar' } to the top of the pipeline block and confirm both stages print bar. If you run distributed builds, add a different agent { label 'other' } to stage two and test whether any script-set env.* values survive the node switch — expect that they may not.
Claims about specific plugin interactions (EnvInject, Config File Provider, credential bindings) vary by plugin version, so treat those as per-installation behavior to verify rather than universal rules. The core scoping rule itself, however, is not version-dependent.
Use comments to ask for clarification. Post a solution as an answer.
No question comments on this page.