jenkinsci / jenkinsci/workflow-cps-plugin

[JENKINS-68646] Delegate of cloned closure cannot be modified

Open
#1,632 3 comments 0 reactions 0 assignees View on GitHub
component:workflow-cps-plugin imported-jira-issue priority:minor resolution:unresolved
Dominant language
Java
Stars
186
Forks
213
Avg merge
12h 12m
Merged PRs (30d)
8

Description

I experienced a rather strange and, as far as I can tell, erroneous behavior when cloning a closure. To reproduce, create a Pipeline job with the following simple Pipeline script:

node {

  Closure c1 = { echo "someValue: ${someValue}" }
    c1.delegate = [someValue:1]
    c1.call()
  Closure c2 = c1.clone()
    c2.delegate = [someValue:2]
  c2.call()
}

Closure c1 refers to variable someValue which is resolved through its delegate. However, cloning c1 and setting a different delegate produces the same output:

```
Started by user admin
[Pipeline] Start of Pipeline
[Pipeline] node
Running on Jenkins in /var/jenkins_home/workspace/ClosureClone
[Pipeline] {
[Pipeline] echo
someValue: 1
[Pipeline] echo
someValue: 1
[Pipeline] }
[Pipeline] // node
[Pipeline] End of Pipeline
Finished: SUCCESS
```

Running this code directly with Groovy (versions >= 2.x) produces the correct result, which is why I assume that it must be caused by Jenkins:

```
someValue: 1
someValue: 2
```

---
Originally reported by p9r, imported from: Delegate of cloned closure cannot be modified


  • status: Open
  • priority: Minor
  • component(s): workflow-cps-plugin
  • resolution: Unresolved
  • votes: 0
  • watchers: 2
  • imported: 2025-12-07

Raw content of original issue

I experienced a rather strange and, as far as I can tell, erroneous behavior when cloning a closure. To reproduce, create a Pipeline job with the following simple Pipeline script:



node {

  Closure c1 = { echo "someValue: ${someValue}" }
    c1.delegate = [someValue:1]
    c1.call()
  Closure c2 = c1.clone()
    c2.delegate = [someValue:2]
  c2.call()
}


Closure c1 refers to variable someValue which is resolved through its delegate. However, cloning c1 and setting a different delegate produces the same output:



Started by user admin

[Pipeline] Start of Pipeline
[Pipeline] node
Running on Jenkins in /var/jenkins_home/workspace/ClosureClone
[Pipeline] {
[Pipeline] echo
someValue: 1
[Pipeline] echo
someValue: 1
[Pipeline] }
[Pipeline] // node
[Pipeline] End of Pipeline
Finished: SUCCESS


Running this code directly with Groovy (versions >= 2.x) produces the correct result, which is why I assume that it must be caused by Jenkins:



someValue: 1

someValue: 2

environment

```
Jenkins: 2.349 (installed via Docker Hub)

OS: Linux - 4.14.276-211.499.amzn2.x86_64

---

ace-editor:1.1

antisamy-markup-formatter:2.7

apache-httpcomponents-client-4-api:4.5.13-1.0

bootstrap5-api:5.1.3-7

bouncycastle-api:2.26

branch-api:2.1046.v0ca_37783ecc5

build-timeout:1.21

caffeine-api:2.9.3-65.v6a_47d0f4d1fe

checks-api:1.7.4

cloudbees-folder:6.722.v8165b_a_cf25e9

command-launcher:84.v4a_97f2027398

credentials:1129.vef26f5df883c

credentials-binding:523.vd859a_4b_122e6

display-url-api:2.3.6

durable-task:496.va67c6f9eefa7

echarts-api:5.3.2-2

font-awesome-api:6.1.1-1

git-client:3.11.0

handlebars:3.0.8

jackson2-api:2.13.3-285.vc03c0256d517

javax-activation-api:1.2.0-3

javax-mail-api:1.6.2-6

jaxb:2.3.6-1

jdk-tool:1.5

jquery3-api:3.6.0-4

jsch:0.1.55.2

junit:1119.va_a_5e9068da_d7

mailer:414.vcc4c33714601

matrix-auth:3.1.2

matrix-project:771.v574584b_39e60

momentjs:1.1.1

pam-auth:1.8

pipeline-build-step:2.18

pipeline-graph-analysis:195.v5812d95a_a_2f9

pipeline-groovy-lib:591.v3a_7f422b_d058

pipeline-input-step:448.v37cea_9a_10a_70

pipeline-milestone-step:101.vd572fef9d926

pipeline-model-api:2.2086.v12b_420f036e5

pipeline-model-definition:2.2086.v12b_420f036e5

pipeline-model-extensions:2.2086.v12b_420f036e5

pipeline-rest-api:2.24

pipeline-stage-step:293.v200037eefcd5

pipeline-stage-tags-metadata:2.2086.v12b_420f036e5

pipeline-stage-view:2.24

plain-credentials:1.8

plugin-util-api:2.17.0

popper2-api:2.11.5-2

resource-disposer:0.19

scm-api:608.vfa_f971c5a_a_e9

script-security:1175.v4b_d517d6db_f0

snakeyaml-api:1.30.1

ssh-credentials:277.v95c2fec1c047

sshd:3.237.v883d165a_c1d3

structs:318.va_f3ccb_729b_71

timestamper:1.17

token-macro:293.v283932a_0a_b_49

trilead-api:1.57.v6e90e07157e1

variant:1.4

workflow-aggregator:581.v0c46fa_697ffd

workflow-api:1153.vb_912c0e47fb_a_

workflow-basic-steps:948.v2c72a_091b_b_68

workflow-cps:2706.v71dd22b_c5a_a_2

workflow-durable-task-step:1139.v252a_e12e8463

workflow-job:1182.v60a_e6279b_579

workflow-multibranch:716.vc692a_e52371b_

workflow-scm-step:400.v6b_89a_1317c9a_

workflow-step-api:625.vd896b_f445a_f8

workflow-support:820.vd1a_6cc65ef33

ws-cleanup:0.42
```

Contributor guide

Open the contributing guide

Research direction

Start by reproducing the behavior with the Pipeline script in the issue and compare it with the direct Groovy result. Then trace the workflow-cps implementation responsible for cloned closures and delegate resolution; done means the cloned closure uses its newly assigned delegate and the reproduction prints someValue: 1 followed by someValue: 2.

Written by the indexing model from the issue text.

Assessment

Tech stack
groovy, java
Domain
backend, ci-cd
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.