Uploaded image for project: 'Jenkins'
  1. Jenkins
  2. JENKINS-50736

Calling another vars step in inheritance context fails with MissingMethodException

    • Icon: Bug Bug
    • Resolution: Unresolved
    • Icon: Major Major
    • workflow-cps-plugin
    • None
    • The latest and greatest, e.g. Jenkins (core) 2.115, workflow-cps 2.47

      Like in JENKINS-50731:

      Thanks to the fix of JENKINS-45982 I dared to continue with one of my original approaches using inheritance in shared Jenkins pipeline library classes, but stumbled over this problem.

      I am not sure anymore (updated) whether or not this is really a bug: because I had already "qualifiyied" calls to 'acme.<steps>' with the script context (or so) also before switching back to using inheritance (thanks to the fix of JENKINS-45982) SpecialBuild below was basically duplicating things of Build like this:

      class SpecialBuild {
      
        def script
        def acme
      
        SpecialBuild(def script) {
          this.script = script
          this.acme = script.acme
        }
      
        void build() {
          acme.build() { // ! Using the 'acme.build' step from 'vars/acme.groovy'
            script.node {
              acme.skipableStage("init") { // Direct usage of 'acme.skipableStage' step worked
                script.echo "acme 'Pipeline from SCM Script'"
              }
      
              acme.skipableStage('checkout') { // Direct usage of 'acme.skipableStage' step worked
                acme.svnCheckout('UpdateWithCleanUpdater')
              }
            }
          }
        }
        
      }
      

      How to reproduce?

      (I tried to include only minimal things and have not tested it after this "thinning out", so maybe there are small mistakes...)

      "Jenkinsfile"
      #!/usr/bin/env groovy
      
      echo 'Sandbox pipeline'
      
      @Library('acme-shared-library') _
      
      acme.specialBuild() {
      }
      
      Classes in shared pipeline library ('src' section)
      • 'src/Build.groovy'
        #!/usr/bin/env groovy
        
        class Build implements Serializable {
        
          def script
          def acme
        
          Build(def script) {
            this.script = Objects.requireNonNull(script, 'script must not be null')
            this.acme = script.acme
          }
        
          void build(Closure body) {
            try {
              body()
            } catch (e) {
            	acme.notifyFailing(...) // Direct access/usage of 'acme' works here
        
            	// While there would be no need to re-throw the exception to propagate the error (because the build result must be set
            	// to failure for email-ext anyhow before), re-throw it for e.g. script approval requests:
            	throw e
            }
          }
        
        }
        
      • 'src/SpecialBuild.groovy'
        #!/usr/bin/env groovy
        
        class SpecialBuild extends Build {
        
          SpecialBuild(def script) {
            super(script)
          }
        
          void build() {
            super.build() { // Mind this instead of 'acme.build()' like before using inheritance
              script.node {
                script.acme.skipableStage("init") { // This works
                  script.echo "acme 'Pipeline from SCM Script'"
                }
        
                acme.skipableStage('checkout') { // ! This does NOT work
                  acme.svnCheckout('UpdateWithCleanUpdater')
                }
              }
            }
          }
          
        }
        
      Corresponding steps in shared pipeline library ('vars' section)
      • 'vars/acme.groovy'
        #!/usr/bin/env groovy
        
        void svnCheckout(String workspaceUpdater = 'UpdateUpdater') {
          // ...
        }
        
        void build(Map args, Closure body) {
          // ...
          def build = new Build(this)
          build.build(body)
        }
        
        void skipableStage(String stageName, Closure body) {
          skipableStage(stageName, false, body)
        }
        void skipableStage(String stageName, def skipCondition, Closure body) {
          skipableStage(stageName, skipCondition, null, body)
        }
        void skipableStage(String stageName, Closure skipBody, Closure body) {
          skipableStage(stageName, false, skipBody, body)
        }
        void skipableStage(String stageName, def skipCondition, Closure skipBody, Closure body) {
          // ...
        }
        
        void specialBuild() {
          // ...
          def acmeSpecialBuild = new SpecialBuild(this)
          acmeSpecialBuild.build()
        }
        
        void notifyFailing(...) { ... }
        

      Current log/error

      Note that this slightly differs to what would expect as it is from the original problem (with less reduced shared library code).

      ...
      [Pipeline] echo
      Sandbox pipeline
      [Pipeline] node
      Running on Jenkins in /var/lib/jenkins/workspace/Sandbox/acme.buildDockerImage
      [Pipeline] {
      [Pipeline] stage
      [Pipeline] { (init)
      [Pipeline] echo
      acme 'Pipeline from SCM Script'
      [Pipeline] }
      [Pipeline] // stage
      [Pipeline] }
      [Pipeline] // node
      [Pipeline] echo
      Pipeline problem: Build failed (init) due to: "groovy.lang.MissingMethodException: No signature of method: static acme.skipableStage() is applicable for argument types: (java.lang.String, org.jenkinsci.plugins.workflow.cps.CpsClosure2) values: [checkout, org.jenkinsci.plugins.workflow.cps.CpsClosure2@4faabfc3]
      Possible solutions: skipableStage(java.lang.String, groovy.lang.Closure), skipableStage(java.lang.String, groovy.lang.Closure, groovy.lang.Closure), skipableStage(java.lang.String, java.lang.Object, groovy.lang.Closure), skipableStage(java.lang.String, java.lang.Object, groovy.lang.Closure, groovy.lang.Closure)" => Please check the "Console/Log Output" => Failure notification will be sent...
      ...
      [Pipeline] // stage
      [Pipeline] End of Pipeline
      hudson.remoting.ProxyException: groovy.lang.MissingMethodException: No signature of method: static acme.skipableStage() is applicable for argument types: (java.lang.String, org.jenkinsci.plugins.workflow.cps.CpsClosure2) values: [checkout, org.jenkinsci.plugins.workflow.cps.CpsClosure2@4faabfc3]
      Possible solutions: skipableStage(java.lang.String, groovy.lang.Closure), skipableStage(java.lang.String, groovy.lang.Closure, groovy.lang.Closure), skipableStage(java.lang.String, java.lang.Object, groovy.lang.Closure), skipableStage(java.lang.String, java.lang.Object, groovy.lang.Closure, groovy.lang.Closure)
      	at groovy.lang.MetaClassImpl.invokeStaticMissingMethod(MetaClassImpl.java:1501)
      	at groovy.lang.MetaClassImpl.invokeStaticMethod(MetaClassImpl.java:1487)
      	at org.codehaus.groovy.runtime.callsite.StaticMetaClassSite.call(StaticMetaClassSite.java:53)
      	at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCall(CallSiteArray.java:48)
      	at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:113)
      	at com.cloudbees.groovy.cps.sandbox.DefaultInvoker.methodCall(DefaultInvoker.java:20)
      	at SpecialBuild.build(file:/var/lib/jenkins/jobs/Sandbox/jobs/acme.build/builds/12/libs/acme-shared-library/src/SpecialBuild.groovy:??)
      	at ___cps.transform___(Native Method)
      	at com.cloudbees.groovy.cps.impl.ContinuationGroup.methodCall(ContinuationGroup.java:57)
      	at com.cloudbees.groovy.cps.impl.FunctionCallBlock$ContinuationImpl.dispatchOrArg(FunctionCallBlock.java:109)
      	at com.cloudbees.groovy.cps.impl.FunctionCallBlock$ContinuationImpl.fixArg(FunctionCallBlock.java:82)
      	at sun.reflect.GeneratedMethodAccessor206.invoke(Unknown Source)
      	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
      	at java.lang.reflect.Method.invoke(Method.java:498)
      	at com.cloudbees.groovy.cps.impl.ContinuationPtr$ContinuationImpl.receive(ContinuationPtr.java:72)
      	at com.cloudbees.groovy.cps.impl.ClosureBlock.eval(ClosureBlock.java:46)
      	at com.cloudbees.groovy.cps.Next.step(Next.java:83)
      	at com.cloudbees.groovy.cps.Continuable$1.call(Continuable.java:174)
      	at com.cloudbees.groovy.cps.Continuable$1.call(Continuable.java:163)
      	at org.codehaus.groovy.runtime.GroovyCategorySupport$ThreadCategoryInfo.use(GroovyCategorySupport.java:122)
      	at org.codehaus.groovy.runtime.GroovyCategorySupport.use(GroovyCategorySupport.java:261)
      	at com.cloudbees.groovy.cps.Continuable.run0(Continuable.java:163)
      	at org.jenkinsci.plugins.workflow.cps.SandboxContinuable.access$101(SandboxContinuable.java:34)
      	at org.jenkinsci.plugins.workflow.cps.SandboxContinuable.lambda$run0$0(SandboxContinuable.java:59)
      	at org.jenkinsci.plugins.scriptsecurity.sandbox.groovy.GroovySandbox.runInSandbox(GroovySandbox.java:108)
      	at org.jenkinsci.plugins.workflow.cps.SandboxContinuable.run0(SandboxContinuable.java:58)
      	at org.jenkinsci.plugins.workflow.cps.CpsThread.runNextChunk(CpsThread.java:174)
      	at org.jenkinsci.plugins.workflow.cps.CpsThreadGroup.run(CpsThreadGroup.java:332)
      	at org.jenkinsci.plugins.workflow.cps.CpsThreadGroup.access$200(CpsThreadGroup.java:83)
      	at org.jenkinsci.plugins.workflow.cps.CpsThreadGroup$2.call(CpsThreadGroup.java:244)
      	at org.jenkinsci.plugins.workflow.cps.CpsThreadGroup$2.call(CpsThreadGroup.java:232)
      	at org.jenkinsci.plugins.workflow.cps.CpsVmExecutorService$2.call(CpsVmExecutorService.java:64)
      	at java.util.concurrent.FutureTask.run(FutureTask.java:266)
      	at hudson.remoting.SingleLaneExecutorService$1.run(SingleLaneExecutorService.java:131)
      	at jenkins.util.ContextResettingExecutorService$1.run(ContextResettingExecutorService.java:28)
      	at jenkins.security.ImpersonatingExecutorService$1.run(ImpersonatingExecutorService.java:59)
      	at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511)
      	at java.util.concurrent.FutureTask.run(FutureTask.java:266)
      	at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
      	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
      	at java.lang.Thread.run(Thread.java:748)
      Finished: FAILURE
      

      Workaround that works:

      • Instead of calling acme.skipableStage(...) in SpecialBuild.build() => call script.acme.skipableStage(...)

          [JENKINS-50736] Calling another vars step in inheritance context fails with MissingMethodException

          Maybe related to JENKINS-34428 and/or JENKINS-50731

          Reinhold Füreder added a comment - Maybe related to JENKINS-34428 and/or JENKINS-50731

          Andrew Bayer added a comment -

          So I've been looking at something similar to this - it seems that this is due to JENKINS-31484. It looks like if you switch to protected def acme, it may work?

          Andrew Bayer added a comment - So I've been looking at something similar to this - it seems that this is due to JENKINS-31484 . It looks like if you switch to protected def acme , it may work?

          Frankly, I don't think so: as def acme is already public, changing it to protected def acme should not help.

          Sorry for the very lengthy and potentially confusing issue description; maybe due to getting doubts whether or not this is a bug, I made some re-writes and adaptions later on, which may not made the issue description clearer... => I'll try to properly re-produce it and then I'll try your protected guess as well...

          Reinhold Füreder added a comment - Frankly, I don't think so: as def acme is already public, changing it to protected def acme should not help. Sorry for the very lengthy and potentially confusing issue description; maybe due to getting doubts whether or not this is a bug, I made some re-writes and adaptions later on, which may not made the issue description clearer... => I'll try to properly re-produce it and then I'll try your protected guess as well...

          Andrew Bayer added a comment -

          You can also try an explicit public - if I’m right, this is due to weirdness around how Groovy treats a field with no modifier and how CPS tries to avoid stack overflows...

          Andrew Bayer added a comment - You can also try an explicit public - if I’m right, this is due to weirdness around how Groovy treats a field with no modifier and how CPS tries to avoid stack overflows...

          Andrew Bayer added a comment -

          Throwing some notes here - first, this is impossible to recreate directly in a single source file, even with multiple classes in it. I believe this is because the CPS transformation here in the subclass happens before the autogenerated getter method is added to the superclass when they're all in the same source file. You can recreate it in a single file by either adding a getter method to the superclass directly. You can create by referencing the field in the subclasses with the this.@someField attribute syntax, but I believe that fails in vanilla Groovy too, so eh.

          What's actually happening is that we're actually calling (via some layers of abstraction) InvokerHelper.getAttribute(object, name), which ends up getting the MetaBeanProperty for that object/name combo. And the field field of that MetaBeanProperty is null. This is the same behavior you get in vanilla Groovy if you do this.@someField in the subclass. So the problem seems to be that you can't actually call InvokerHelper.getAttribute(object, name) for a field on a superclass, and our hacks to avoid recursion hell with getter methods (which I think was intended primarily to deal with explicit getters, not autogenerated getters, but don't quote me on that) will end up doing that.

          How to fix this? Well, I've got a couple hacks I've tried that seem to "fix" this for some value of "fixed" - most notably changing DefaultInvoker#getAttribute(lhs, name) to catch MissingFieldException when it shows up and try forcing a MetaClass#getAttribute call with InvokerHelper.getMetaClass(lhs.getClass().getSuperclass()), recursing on until we get to Object.class. But that feels really really dirty, so I'm trying to think of something better.

          Andrew Bayer added a comment - Throwing some notes here - first, this is impossible to recreate directly in a single source file, even with multiple classes in it. I believe this is because the CPS transformation here in the subclass happens before the autogenerated getter method is added to the superclass when they're all in the same source file. You can recreate it in a single file by either adding a getter method to the superclass directly. You can create by referencing the field in the subclasses with the this.@someField attribute syntax, but I believe that fails in vanilla Groovy too, so eh. What's actually happening is that we're actually calling (via some layers of abstraction) InvokerHelper.getAttribute(object, name) , which ends up getting the MetaBeanProperty for that object/name combo. And the field field of that MetaBeanProperty is null. This is the same behavior you get in vanilla Groovy if you do this.@someField in the subclass. So the problem seems to be that you can't actually call InvokerHelper.getAttribute(object, name) for a field on a superclass, and our hacks to avoid recursion hell with getter methods (which I think was intended primarily to deal with explicit getters, not autogenerated getters, but don't quote me on that) will end up doing that. How to fix this? Well, I've got a couple hacks I've tried that seem to "fix" this for some value of "fixed" - most notably changing DefaultInvoker#getAttribute(lhs, name) to catch MissingFieldException when it shows up and try forcing a MetaClass#getAttribute call with InvokerHelper.getMetaClass(lhs.getClass().getSuperclass()) , recursing on until we get to Object.class . But that feels really really dirty, so I'm trying to think of something better.

          Jesse Glick added a comment -

          acme is an attribute of WorkflowScript. SpecialBuild is a top-level class. Therefore unqualified acme is not resolvable. That is not a bug.

          If unqualified acme does work inside Build, that would be a bug. Unless it were a field. Which it does not look like, since you are using def, which is used for defining local variables. I was not aware that is even syntactically legal in Groovy. Declare a type, or use @Field, or do not declare it at all and just refer to it with @acme notation.

          I am pretty confident this is all just a user error.

          Jesse Glick added a comment - acme is an attribute of WorkflowScript . SpecialBuild is a top-level class. Therefore unqualified acme is not resolvable. That is not a bug. If unqualified acme does work inside Build , that would be a bug. Unless it were a field. Which it does not look like, since you are using def , which is used for defining local variables. I was not aware that is even syntactically legal in Groovy. Declare a type, or use @Field , or do not declare it at all and just refer to it with @acme notation. I am pretty confident this is all just a user error.

          Thanks for your feedback.

          One of the main reasons – why I was nonetheless filing this issue after some initial hesitation – was the error message, which somehow reads as if it did not find the required method, but one of the possible solutions actually is the right one as it has the right signature (and should be just taken):

          hudson.remoting.ProxyException: groovy.lang.MissingMethodException: No signature of method: static acme.skipableStage() is applicable for argument types: (java.lang.String, org.jenkinsci.plugins.workflow.cps.CpsClosure2) values: [checkout, org.jenkinsci.plugins.workflow.cps.CpsClosure2@4faabfc3]
          Possible solutions: skipableStage(java.lang.String, groovy.lang.Closure), skipableStage(java.lang.String, groovy.lang.Closure, groovy.lang.Closure), skipableStage(java.lang.String, java.lang.Object, groovy.lang.Closure), skipableStage(java.lang.String, java.lang.Object, groovy.lang.Closure, groovy.lang.Closure)
          

          And based on jglick's comment I must admit that my issue description was too confusing or badly updated, because SpecialBuild is NOT a top-level class in the failure scenario; unfortunately I just started the issue description with the old workaround code that worked where SpecialBuild was a top-level class and I did not use inheritance.

          Therefore I nonetheless made a proper re-producer for you:

          • slightly simpler as in the original description above
          • and really tested
          • but not using any tricks (that I may not understand) to "maybe" recreate it in a single file

          So here it is:

          1. Pipeline library:
            1. "vars/acme.groovy"
              #!/usr/bin/env groovy
              
              import com.acme.Build
              import com.acme.SpecialBuild
              
              void doSomething() {
                echo 'doSomething...'
              }
              
              void build(Closure body) {
                def build = new Build(this)
                build.build(body)
              }
              
              void specialBuild() {
                def acmeSpecialBuild = new SpecialBuild(this)
                acmeSpecialBuild.build()
              }
              
            2. com.acme.Build in "src/com/acme/Build.groovy"
              package com.acme
              
              class Build implements Serializable {
              
                def script
                def acme
              
                Build(def script) {
                  this.script = Objects.requireNonNull(script, 'script must not be null')
                  this.acme = script.acme
                }
              
                void build(Closure body) {
                  script.stage('pre stage defined in Build') {
                    script.echo 'in Build.build #1 before acme.doSomething()'
                    acme.doSomething()
                  }
              
                  body()
              
                  script.stage('post stage defined in Build') {
                    script.echo 'in Build.build #2 before acme.doSomething()'
                    acme.doSomething()
                  }
                }
              
              }
              
            3. com.acme.SpecialBuild in "src/com/acme/SpecialBuild.groovy"
              package com.acme
              
              class SpecialBuild extends Build {
              
                SpecialBuild(def script) {
                  super(script)
                }
              
                void build() {
                  super.build() { // Mind this instead of 'acme.build()' like before using inheritance
                    script.node {
                      script.stage("stage good") {
                        script.echo "some echo in stage good"
                        script.acme.doSomething() // This works
                      }
              
                      script.stage('stage bad') {
                        script.echo "some echo in stage bad"
                        acme.doSomething() // ! This does NOT work
                      }
                    }
                  }
                }
              
              }
              
          2. "Jenkinsfile"
            #!/usr/bin/env groovy
            
            @Library('acme-shared-library@branches/JENKINS-50736') _
            
            // This works:
            /*
            acme.build() {
              stage('stage defined in Jenkinsfile') {
                acme.doSomething()
              }
            }
            */
            
            // ! This does NOT work:
            acme.specialBuild()
            

          So this is the error message and the interesting top part of the stacktrace:

          hudson.remoting.ProxyException: groovy.lang.MissingMethodException: No signature of method: static acme.doSomething() is applicable for argument types: () values: []
          Possible solutions: doSomething(), toString(), toString()
          	at groovy.lang.MetaClassImpl.invokeStaticMissingMethod(MetaClassImpl.java:1501)
          	at groovy.lang.MetaClassImpl.invokeStaticMethod(MetaClassImpl.java:1487)
          	at org.codehaus.groovy.runtime.callsite.StaticMetaClassSite.call(StaticMetaClassSite.java:53)
          	at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCall(CallSiteArray.java:48)
          	at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:113)
          	at com.cloudbees.groovy.cps.sandbox.DefaultInvoker.methodCall(DefaultInvoker.java:20)
          	at com.acme.SpecialBuild.build(file:/var/lib/jenkins/jobs/Sandbox/jobs/JENKINS-50736/builds/18/libs/xortex-shared-library/src/com/acme/SpecialBuild.groovy:19)
          	at ___cps.transform___(Native Method)
          	...
          

          And for com.acme.Build#acme I tried these alternative field/property declaration approaches, but the error did not change at all:

          • def acme
          • public def acme
          • Object acme
          • public Object acme

          And this is (almost) the whole log output including full stacktrace:

          ...
          
          [Pipeline] stage
          [Pipeline] { (pre stage defined in Build)
          [Pipeline] echo
          in Build.build #1 before acme.doSomething()
          [Pipeline] echo
          doSomething...
          [Pipeline] }
          [Pipeline] // stage
          [Pipeline] node
          Running on Jenkins in /var/lib/jenkins/workspace/Sandbox/JENKINS-50736
          [Pipeline] {
          [Pipeline] stage
          [Pipeline] { (stage good)
          [Pipeline] echo
          some echo in stage good
          [Pipeline] echo
          doSomething...
          [Pipeline] }
          [Pipeline] // stage
          [Pipeline] stage
          [Pipeline] { (stage bad)
          [Pipeline] echo
          some echo in stage bad
          [Pipeline] }
          [Pipeline] // stage
          [Pipeline] }
          [Pipeline] // node
          [Pipeline] End of Pipeline
          hudson.remoting.ProxyException: groovy.lang.MissingMethodException: No signature of method: static acme.doSomething() is applicable for argument types: () values: []
          Possible solutions: doSomething(), toString(), toString()
          	at groovy.lang.MetaClassImpl.invokeStaticMissingMethod(MetaClassImpl.java:1501)
          	at groovy.lang.MetaClassImpl.invokeStaticMethod(MetaClassImpl.java:1487)
          	at org.codehaus.groovy.runtime.callsite.StaticMetaClassSite.call(StaticMetaClassSite.java:53)
          	at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCall(CallSiteArray.java:48)
          	at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:113)
          	at com.cloudbees.groovy.cps.sandbox.DefaultInvoker.methodCall(DefaultInvoker.java:20)
          	at com.acme.SpecialBuild.build(file:/var/lib/jenkins/jobs/Sandbox/jobs/JENKINS-50736/builds/18/libs/acme-shared-library/src/com/acme/SpecialBuild.groovy:19)
          	at ___cps.transform___(Native Method)
          	at com.cloudbees.groovy.cps.impl.ContinuationGroup.methodCall(ContinuationGroup.java:57)
          	at com.cloudbees.groovy.cps.impl.FunctionCallBlock$ContinuationImpl.dispatchOrArg(FunctionCallBlock.java:109)
          	at com.cloudbees.groovy.cps.impl.FunctionCallBlock$ContinuationImpl.fixName(FunctionCallBlock.java:77)
          	at sun.reflect.GeneratedMethodAccessor391.invoke(Unknown Source)
          	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
          	at java.lang.reflect.Method.invoke(Method.java:498)
          	at com.cloudbees.groovy.cps.impl.ContinuationPtr$ContinuationImpl.receive(ContinuationPtr.java:72)
          	at com.cloudbees.groovy.cps.impl.ConstantBlock.eval(ConstantBlock.java:21)
          	at com.cloudbees.groovy.cps.Next.step(Next.java:83)
          	at com.cloudbees.groovy.cps.Continuable$1.call(Continuable.java:174)
          	at com.cloudbees.groovy.cps.Continuable$1.call(Continuable.java:163)
          	at org.codehaus.groovy.runtime.GroovyCategorySupport$ThreadCategoryInfo.use(GroovyCategorySupport.java:122)
          	at org.codehaus.groovy.runtime.GroovyCategorySupport.use(GroovyCategorySupport.java:261)
          	at com.cloudbees.groovy.cps.Continuable.run0(Continuable.java:163)
          	at org.jenkinsci.plugins.workflow.cps.SandboxContinuable.access$101(SandboxContinuable.java:34)
          	at org.jenkinsci.plugins.workflow.cps.SandboxContinuable.lambda$run0$0(SandboxContinuable.java:59)
          	at org.jenkinsci.plugins.scriptsecurity.sandbox.groovy.GroovySandbox.runInSandbox(GroovySandbox.java:108)
          	at org.jenkinsci.plugins.workflow.cps.SandboxContinuable.run0(SandboxContinuable.java:58)
          	at org.jenkinsci.plugins.workflow.cps.CpsThread.runNextChunk(CpsThread.java:174)
          	at org.jenkinsci.plugins.workflow.cps.CpsThreadGroup.run(CpsThreadGroup.java:332)
          	at org.jenkinsci.plugins.workflow.cps.CpsThreadGroup.access$200(CpsThreadGroup.java:83)
          	at org.jenkinsci.plugins.workflow.cps.CpsThreadGroup$2.call(CpsThreadGroup.java:244)
          	at org.jenkinsci.plugins.workflow.cps.CpsThreadGroup$2.call(CpsThreadGroup.java:232)
          	at org.jenkinsci.plugins.workflow.cps.CpsVmExecutorService$2.call(CpsVmExecutorService.java:64)
          	at java.util.concurrent.FutureTask.run(FutureTask.java:266)
          	at hudson.remoting.SingleLaneExecutorService$1.run(SingleLaneExecutorService.java:131)
          	at jenkins.util.ContextResettingExecutorService$1.run(ContextResettingExecutorService.java:28)
          	at jenkins.security.ImpersonatingExecutorService$1.run(ImpersonatingExecutorService.java:59)
          	at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511)
          	at java.util.concurrent.FutureTask.run(FutureTask.java:266)
          	at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
          	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
          	at java.lang.Thread.run(Thread.java:748)
          Finished: FAILURE
          

          Therefore I still have hope that (a) this might be fixable and be fixed sooner or later, and (b) claim it is not "just a user error"...

          Reinhold Füreder added a comment - Thanks for your feedback. One of the main reasons – why I was nonetheless filing this issue after some initial hesitation – was the error message, which somehow reads as if it did not find the required method, but one of the possible solutions actually is the right one as it has the right signature (and should be just taken): hudson.remoting.ProxyException: groovy.lang.MissingMethodException: No signature of method: static acme.skipableStage() is applicable for argument types: (java.lang.String, org.jenkinsci.plugins.workflow.cps.CpsClosure2) values: [checkout, org.jenkinsci.plugins.workflow.cps.CpsClosure2@4faabfc3] Possible solutions: skipableStage(java.lang.String, groovy.lang.Closure), skipableStage(java.lang.String, groovy.lang.Closure, groovy.lang.Closure), skipableStage(java.lang.String, java.lang.Object, groovy.lang.Closure), skipableStage(java.lang.String, java.lang.Object, groovy.lang.Closure, groovy.lang.Closure) And based on jglick 's comment I must admit that my issue description was too confusing or badly updated, because SpecialBuild is NOT a top-level class in the failure scenario; unfortunately I just started the issue description with the old workaround code that worked where SpecialBuild was a top-level class and I did not use inheritance. Therefore I nonetheless made a proper re-producer for you: slightly simpler as in the original description above and really tested but not using any tricks (that I may not understand) to "maybe" recreate it in a single file So here it is: Pipeline library: "vars/acme.groovy" #!/usr/bin/env groovy import com.acme.Build import com.acme.SpecialBuild void doSomething() { echo 'doSomething...' } void build(Closure body) { def build = new Build( this ) build.build(body) } void specialBuild() { def acmeSpecialBuild = new SpecialBuild( this ) acmeSpecialBuild.build() } com.acme.Build in "src/com/acme/Build.groovy" package com.acme class Build implements Serializable { def script def acme Build(def script) { this .script = Objects.requireNonNull(script, 'script must not be null ' ) this .acme = script.acme } void build(Closure body) { script.stage( 'pre stage defined in Build' ) { script.echo 'in Build.build #1 before acme.doSomething()' acme.doSomething() } body() script.stage( 'post stage defined in Build' ) { script.echo 'in Build.build #2 before acme.doSomething()' acme.doSomething() } } } com.acme.SpecialBuild in "src/com/acme/SpecialBuild.groovy" package com.acme class SpecialBuild extends Build { SpecialBuild(def script) { super (script) } void build() { super .build() { // Mind this instead of 'acme.build()' like before using inheritance script.node { script.stage( "stage good" ) { script.echo "some echo in stage good" script.acme.doSomething() // This works } script.stage( 'stage bad' ) { script.echo "some echo in stage bad" acme.doSomething() // ! This does NOT work } } } } } "Jenkinsfile" #!/usr/bin/env groovy @Library( 'acme-shared-library@branches/JENKINS-50736' ) _ // This works: /* acme.build() { stage( 'stage defined in Jenkinsfile' ) { acme.doSomething() } } */ // ! This does NOT work: acme.specialBuild() So this is the error message and the interesting top part of the stacktrace: hudson.remoting.ProxyException: groovy.lang.MissingMethodException: No signature of method: static acme.doSomething() is applicable for argument types: () values: [] Possible solutions: doSomething(), toString(), toString() at groovy.lang.MetaClassImpl.invokeStaticMissingMethod(MetaClassImpl.java:1501) at groovy.lang.MetaClassImpl.invokeStaticMethod(MetaClassImpl.java:1487) at org.codehaus.groovy.runtime.callsite.StaticMetaClassSite.call(StaticMetaClassSite.java:53) at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCall(CallSiteArray.java:48) at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:113) at com.cloudbees.groovy.cps.sandbox.DefaultInvoker.methodCall(DefaultInvoker.java:20) at com.acme.SpecialBuild.build(file:/var/lib/jenkins/jobs/Sandbox/jobs/JENKINS-50736/builds/18/libs/xortex-shared-library/src/com/acme/SpecialBuild.groovy:19) at ___cps.transform___(Native Method) ... And for com.acme.Build#acme I tried these alternative field/property declaration approaches, but the error did not change at all: def acme public def acme Object acme public Object acme And this is (almost) the whole log output including full stacktrace: ... [Pipeline] stage [Pipeline] { (pre stage defined in Build) [Pipeline] echo in Build.build #1 before acme.doSomething() [Pipeline] echo doSomething... [Pipeline] } [Pipeline] // stage [Pipeline] node Running on Jenkins in /var/lib/jenkins/workspace/Sandbox/JENKINS-50736 [Pipeline] { [Pipeline] stage [Pipeline] { (stage good) [Pipeline] echo some echo in stage good [Pipeline] echo doSomething... [Pipeline] } [Pipeline] // stage [Pipeline] stage [Pipeline] { (stage bad) [Pipeline] echo some echo in stage bad [Pipeline] } [Pipeline] // stage [Pipeline] } [Pipeline] // node [Pipeline] End of Pipeline hudson.remoting.ProxyException: groovy.lang.MissingMethodException: No signature of method: static acme.doSomething() is applicable for argument types: () values: [] Possible solutions: doSomething(), toString(), toString() at groovy.lang.MetaClassImpl.invokeStaticMissingMethod(MetaClassImpl.java:1501) at groovy.lang.MetaClassImpl.invokeStaticMethod(MetaClassImpl.java:1487) at org.codehaus.groovy.runtime.callsite.StaticMetaClassSite.call(StaticMetaClassSite.java:53) at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCall(CallSiteArray.java:48) at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:113) at com.cloudbees.groovy.cps.sandbox.DefaultInvoker.methodCall(DefaultInvoker.java:20) at com.acme.SpecialBuild.build(file:/var/lib/jenkins/jobs/Sandbox/jobs/JENKINS-50736/builds/18/libs/acme-shared-library/src/com/acme/SpecialBuild.groovy:19) at ___cps.transform___(Native Method) at com.cloudbees.groovy.cps.impl.ContinuationGroup.methodCall(ContinuationGroup.java:57) at com.cloudbees.groovy.cps.impl.FunctionCallBlock$ContinuationImpl.dispatchOrArg(FunctionCallBlock.java:109) at com.cloudbees.groovy.cps.impl.FunctionCallBlock$ContinuationImpl.fixName(FunctionCallBlock.java:77) at sun.reflect.GeneratedMethodAccessor391.invoke(Unknown Source) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.lang.reflect.Method.invoke(Method.java:498) at com.cloudbees.groovy.cps.impl.ContinuationPtr$ContinuationImpl.receive(ContinuationPtr.java:72) at com.cloudbees.groovy.cps.impl.ConstantBlock.eval(ConstantBlock.java:21) at com.cloudbees.groovy.cps.Next.step(Next.java:83) at com.cloudbees.groovy.cps.Continuable$1.call(Continuable.java:174) at com.cloudbees.groovy.cps.Continuable$1.call(Continuable.java:163) at org.codehaus.groovy.runtime.GroovyCategorySupport$ThreadCategoryInfo.use(GroovyCategorySupport.java:122) at org.codehaus.groovy.runtime.GroovyCategorySupport.use(GroovyCategorySupport.java:261) at com.cloudbees.groovy.cps.Continuable.run0(Continuable.java:163) at org.jenkinsci.plugins.workflow.cps.SandboxContinuable.access$101(SandboxContinuable.java:34) at org.jenkinsci.plugins.workflow.cps.SandboxContinuable.lambda$run0$0(SandboxContinuable.java:59) at org.jenkinsci.plugins.scriptsecurity.sandbox.groovy.GroovySandbox.runInSandbox(GroovySandbox.java:108) at org.jenkinsci.plugins.workflow.cps.SandboxContinuable.run0(SandboxContinuable.java:58) at org.jenkinsci.plugins.workflow.cps.CpsThread.runNextChunk(CpsThread.java:174) at org.jenkinsci.plugins.workflow.cps.CpsThreadGroup.run(CpsThreadGroup.java:332) at org.jenkinsci.plugins.workflow.cps.CpsThreadGroup.access$200(CpsThreadGroup.java:83) at org.jenkinsci.plugins.workflow.cps.CpsThreadGroup$2.call(CpsThreadGroup.java:244) at org.jenkinsci.plugins.workflow.cps.CpsThreadGroup$2.call(CpsThreadGroup.java:232) at org.jenkinsci.plugins.workflow.cps.CpsVmExecutorService$2.call(CpsVmExecutorService.java:64) at java.util.concurrent.FutureTask.run(FutureTask.java:266) at hudson.remoting.SingleLaneExecutorService$1.run(SingleLaneExecutorService.java:131) at jenkins.util.ContextResettingExecutorService$1.run(ContextResettingExecutorService.java:28) at jenkins.security.ImpersonatingExecutorService$1.run(ImpersonatingExecutorService.java:59) at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511) at java.util.concurrent.FutureTask.run(FutureTask.java:266) at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624) at java.lang.Thread.run(Thread.java:748) Finished: FAILURE Therefore I still have hope that (a) this might be fixable and be fixed sooner or later, and (b) claim it is not "just a user error"...

            Unassigned Unassigned
            reinholdfuereder Reinhold Füreder
            Votes:
            3 Vote for this issue
            Watchers:
            7 Start watching this issue

              Created:
              Updated: