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

org.codehaus.groovy.control.MultipleCompilationErrorsException: startup failed: General error during class generation: Method code too large! error in pipeline Script

    XMLWordPrintable

    Details

    • Similar Issues:

      Description

      Note from the Maintainers

      There is partial fix for this for Declarative pipelines in pipeline-model-definition-plugin v1.4.0 and later, significantly improved in v1.8.4.  Due to the extent to which it change how pipelines are executed it is turned off by default.  It can be turned on by setting a JVM property (either on the command-line or in Jenkins script console):

      org.jenkinsci.plugins.pipeline.modeldefinition.parser.RuntimeASTTransformer.SCRIPT_SPLITTING_TRANSFORMATION=true 

      As noted, this still works best with a Jenkinsfile with pipeline directive as the only root item in the file.
      Since v1.8.2 this workaround reports an informative error for pipelines using `def` variables before the pipeline directive. Add a @Field annotation to those declaration.
      This workaround generally does NOT work if the pipeline directive inside a shared library method. If this is a scenario you want, please come join the pipeline authoring SIG and we can discuss.

      Please give it a try and provide feedback. 

      Hi,

      We are getting below error in Pipeline which has some 495 lines of groovy code. Initially we assumed that one of our methods has an issue but once we remove any 30-40 lines of Pipeline groovy, this issue is not coming.

      Can you please suggest a quick workaround. It's a blocker for us.

      org.codehaus.groovy.control.MultipleCompilationErrorsException: startup failed:
      General error during class generation: Method code too large!
      
      java.lang.RuntimeException: Method code too large!
      	at groovyjarjarasm.asm.MethodWriter.a(Unknown Source)
      	at groovyjarjarasm.asm.ClassWriter.toByteArray(Unknown Source)
      	at org.codehaus.groovy.control.CompilationUnit$16.call(CompilationUnit.java:815)
      	at org.codehaus.groovy.control.CompilationUnit.applyToPrimaryClassNodes(CompilationUnit.java:1053)
      	at org.codehaus.groovy.control.CompilationUnit.doPhaseOperation(CompilationUnit.java:591)
      	at org.codehaus.groovy.control.CompilationUnit.processPhaseOperations(CompilationUnit.java:569)
      	at org.codehaus.groovy.control.CompilationUnit.compile(CompilationUnit.java:546)
      	at groovy.lang.GroovyClassLoader.doParseClass(GroovyClassLoader.java:298)
      	at groovy.lang.GroovyClassLoader.parseClass(GroovyClassLoader.java:268)
      	at groovy.lang.GroovyShell.parseClass(GroovyShell.java:688)
      	at groovy.lang.GroovyShell.parse(GroovyShell.java:700)
      	at org.jenkinsci.plugins.workflow.cps.CpsGroovyShell.reparse(CpsGroovyShell.java:67)
      	at org.jenkinsci.plugins.workflow.cps.CpsFlowExecution.parseScript(CpsFlowExecution.java:410)
      	at org.jenkinsci.plugins.workflow.cps.CpsFlowExecution.start(CpsFlowExecution.java:373)
      	at org.jenkinsci.plugins.workflow.job.WorkflowRun.run(WorkflowRun.java:213)
      	at hudson.model.ResourceController.execute(ResourceController.java:98)
      	at hudson.model.Executor.run(Executor.java:410)
      
      1 error
      
      	at org.codehaus.groovy.control.ErrorCollector.failIfErrors(ErrorCollector.java:310)
      	at org.codehaus.groovy.control.CompilationUnit.applyToPrimaryClassNodes(CompilationUnit.java:1073)
      	at org.codehaus.groovy.control.CompilationUnit.doPhaseOperation(CompilationUnit.java:591)
      	at org.codehaus.groovy.control.CompilationUnit.processPhaseOperations(CompilationUnit.java:569)
      	at org.codehaus.groovy.control.CompilationUnit.compile(CompilationUnit.java:546)
      	at groovy.lang.GroovyClassLoader.doParseClass(GroovyClassLoader.java:298)
      	at groovy.lang.GroovyClassLoader.parseClass(GroovyClassLoader.java:268)
      	at groovy.lang.GroovyShell.parseClass(GroovyShell.java:688)
      	at groovy.lang.GroovyShell.parse(GroovyShell.java:700)
      	at org.jenkinsci.plugins.workflow.cps.CpsGroovyShell.reparse(CpsGroovyShell.java:67)
      	at org.jenkinsci.plugins.workflow.cps.CpsFlowExecution.parseScript(CpsFlowExecution.java:410)
      	at org.jenkinsci.plugins.workflow.cps.CpsFlowExecution.start(CpsFlowExecution.java:373)
      	at org.jenkinsci.plugins.workflow.job.WorkflowRun.run(WorkflowRun.java:213)
      	at hudson.model.ResourceController.execute(ResourceController.java:98)
      	at hudson.model.Executor.run(Executor.java:410)
      Finished: FAILURE
      

        Attachments

          Issue Links

            Activity

            Hide
            moskovych Oleh Moskovych added a comment - - edited

            Liam Newman, ok, here is small example of my pipeline:

             

            #!/usr/bin/env groovy
            
            //library("jenkins_shared_library@1.0.0")
            
            //@groovy.transform.Field
            String resourcePrefix = new Date().getTime().toString()
            
            //@groovy.transform.Field
            Map dockerParameters = [
                registry: "docker.example.com",
                registryType: "internal",
                images: [
                    image1: [image: "image1", dockerfile: "Dockerfile1"],
                    image2: [image: "image2", dockerfile: "Dockerfile2"]
                ]
            ]
            
            pipeline {
              agent any
              options { skipDefaultCheckout true }
              parameters {
                booleanParam defaultValue: true, description: 'Build & Push image1', name: 'image1'
                booleanParam defaultValue: true, description: 'Build & Push image2', name: 'image2'
              }
            
              stages {
                stage("Prepare") {
                  options { skipDefaultCheckout true }
                  failFast true
                  parallel {
                    stage('Test1') {
                      steps {
                        // All variables available in simple stages and parallel blocks
                        echo "resourcePrefix: ${resourcePrefix}"
                        echo "dockerParameters: ${dockerParameters}"
                      }
                    }
                    stage('Test2') {
                      steps {
                        echo "resourcePrefix: ${resourcePrefix}"
                        echo "dockerParameters: ${dockerParameters}"
                      }
                    }
                  }
                }
            
            
                stage("Docker") {
                  options { skipDefaultCheckout true }
                  matrix {
                    axes {
                      axis {
                        name 'COMPONENT'
                        // Note: these values are the same as described in dockerParameters and params
                        values 'image1', 'image2'
                      }
                    }
                    stages {
                      stage("Build") {
                        when {
                          beforeAgent true
                          expression { params[COMPONENT] == true }
                        }
                        // agent { kubernetes(k8sAgent(name: 'dind')) }
                        steps {
                          // Failing on resourcePrefix/dockerParameters, as it doesn't have Field annotation
                          // Question is: why variables are not available inside matrix?
            
                          echo "resourcePrefix: ${resourcePrefix}"
                          echo "dockerParameters: ${dockerParameters}"
            
                          // Here is one step as example:
                          //dockerBuild(
                          //    image: dockerParameters.images[COMPONENT].image,
                          //    dockerfile: dockerParameters.images[COMPONENT].dockerfile
                          //)
                        }
                      }
                    }
                  }
                }
            
              }
            }
            
            

             

            The result is following:

            stage `Prepare` goes fine anyway - as expected.

            stage `Docker` fails (on each matrix stage) with the message:

            groovy.lang.MissingPropertyException: No such property: resourcePrefix for class: groovy.lang.Binding
            

            Until I do not add annotation: `@groovy.transform.Field`

            The same with `dockerParameters`, where I have map of different values, which are similar and have some common values.

            Note: this is just example, there is parameters, which we use in different stages, and copy-pasting all of them to each stage is not appropriate solution - defining them as common/global outside of `pipeline` block is the only way to do it, isn't it?

             

            Additional info: Version of plugin: 1.8.2 / Jenkins version: 2.235.3 / Any splitting params (described in PR #405) or experimental features was never enabled.

             

            Any ideas?

            Show
            moskovych Oleh Moskovych added a comment - - edited Liam Newman , ok, here is small example of my pipeline:   #!/usr/bin/env groovy //library( "jenkins_shared_library@1.0.0" ) //@groovy.transform.Field String resourcePrefix = new Date().getTime().toString() //@groovy.transform.Field Map dockerParameters = [ registry: "docker.example.com" , registryType: "internal" , images: [ image1: [image: "image1" , dockerfile: "Dockerfile1" ], image2: [image: "image2" , dockerfile: "Dockerfile2" ] ] ] pipeline { agent any options { skipDefaultCheckout true } parameters { booleanParam defaultValue: true , description: 'Build & Push image1' , name: 'image1' booleanParam defaultValue: true , description: 'Build & Push image2' , name: 'image2' } stages { stage( "Prepare" ) { options { skipDefaultCheckout true } failFast true parallel { stage( 'Test1' ) { steps { // All variables available in simple stages and parallel blocks echo "resourcePrefix: ${resourcePrefix}" echo "dockerParameters: ${dockerParameters}" } } stage( 'Test2' ) { steps { echo "resourcePrefix: ${resourcePrefix}" echo "dockerParameters: ${dockerParameters}" } } } } stage( "Docker" ) { options { skipDefaultCheckout true } matrix { axes { axis { name 'COMPONENT' // Note: these values are the same as described in dockerParameters and params values 'image1' , 'image2' } } stages { stage( "Build" ) { when { beforeAgent true expression { params[COMPONENT] == true } } // agent { kubernetes(k8sAgent(name: 'dind' )) } steps { // Failing on resourcePrefix/dockerParameters, as it doesn't have Field annotation // Question is: why variables are not available inside matrix? echo "resourcePrefix: ${resourcePrefix}" echo "dockerParameters: ${dockerParameters}" // Here is one step as example: //dockerBuild( // image: dockerParameters.images[COMPONENT].image, // dockerfile: dockerParameters.images[COMPONENT].dockerfile //) } } } } } } }   The result is following: stage `Prepare` goes fine anyway - as expected. stage `Docker` fails (on each matrix stage) with the message: groovy.lang.MissingPropertyException: No such property: resourcePrefix for class: groovy.lang.Binding Until I do not add annotation: `@groovy.transform.Field` The same with `dockerParameters`, where I have map of different values, which are similar and have some common values. Note: this is just example, there is parameters, which we use in different stages, and copy-pasting all of them to each stage is not appropriate solution - defining them as common/global outside of `pipeline` block is the only way to do it, isn't it?   Additional info: Version of plugin: 1.8.2 / Jenkins version: 2.235.3 / Any splitting params ( described in PR #405 ) or experimental features was never enabled.   Any ideas?
            Hide
            sodul Stephane Odul added a comment - - edited

            We found a partial workaround for our pipelines that need to pass around parameters. We used to define a variable but somehow with `params` and `env` not available switching to a `get_params()` method so that that these values are available by then seems to do the trick.

            Restart from stage is also working as expected.

            Show
            sodul Stephane Odul added a comment - - edited We found a partial workaround for our pipelines that need to pass around parameters. We used to define a variable but somehow with `params` and `env` not available switching to a `get_params()` method so that that these values are available by then seems to do the trick. Restart from stage is also working as expected.
            Hide
            bitwiseman Liam Newman added a comment - - edited

            Stephane Odul
            This is very useful data.
            Can you give an example of what the get_params() form looks like?

            Show
            bitwiseman Liam Newman added a comment - - edited Stephane Odul This is very useful data. Can you give an example of what the get_params() form looks like?
            Hide
            sodul Stephane Odul added a comment - - edited
            def get_params() {
                return [
                    gitParameter(name: 'BRANCH', value: params.BRANCH),
                    string(name: 'FOO', value: env.FOO),
                    booleanParam(name: 'SKIP', value: params.SKIP)
                ]
            }
            
            pipeline {
                ...
                    build(job: 'other/pipeline', propagate: true, wait: true, parameters: get_params())
                ...
            }
            

            Some of our pipelines include a more complex get_build_params():

            def get_build_params(name) {
                return [job: name, propagate: true, wait: true, parameters: get_params())]
            }
            

            So the the build call can be as simple as build(get_build_params()) which greatly simplify our jenkinsfiles and reduces copy pasting, especially for some of our test automation pipelines that orchestrate calling many sub-pipelines. Since the various parameters are pipeline specific we do not really want to put it in the library as it would make it much larger than necessary, furthermore the parameters can be branch specific, which makes using a shared library less ideal.

            Initially we had `@field my_params = [...]`, but that was failing since `env` and `params` are now missing. We tried to move the variable definition to the first stage under a script block, but that would break `restart from stage` since values are not persisted. This alternative approach recreates the same data over and over, but that's pretty lightweight and seems to be fully backward/forward compatible.

            Show
            sodul Stephane Odul added a comment - - edited def get_params() { return [ gitParameter(name: 'BRANCH', value: params.BRANCH), string(name: 'FOO', value: env.FOO), booleanParam(name: 'SKIP', value: params.SKIP) ] } pipeline { ... build(job: 'other/pipeline', propagate: true, wait: true, parameters: get_params()) ... } Some of our pipelines include a more complex get_build_params() : def get_build_params(name) { return [job: name, propagate: true, wait: true, parameters: get_params())] } So the the build call can be as simple as build(get_build_params()) which greatly simplify our jenkinsfiles and reduces copy pasting, especially for some of our test automation pipelines that orchestrate calling many sub-pipelines. Since the various parameters are pipeline specific we do not really want to put it in the library as it would make it much larger than necessary, furthermore the parameters can be branch specific, which makes using a shared library less ideal. Initially we had `@field my_params = [...] `, but that was failing since `env` and `params` are now missing. We tried to move the variable definition to the first stage under a script block, but that would break `restart from stage` since values are not persisted. This alternative approach recreates the same data over and over, but that's pretty lightweight and seems to be fully backward/forward compatible.
            Hide
            moskovych Oleh Moskovych added a comment -

            Liam Newman, I've created new bug as this ticket description doesn't follow with my case of issue:

            https://issues.jenkins.io/browse/JENKINS-64846

            Workaround with Field annotation still force users to fix theirs pipelines, which means - this is breaking changes.

            Show
            moskovych Oleh Moskovych added a comment - Liam Newman , I've created new bug as this ticket description doesn't follow with my case of issue: https://issues.jenkins.io/browse/JENKINS-64846 Workaround with Field annotation still force users to fix theirs pipelines, which means - this is breaking changes.

              People

              Assignee:
              Unassigned Unassigned
              Reporter:
              anudeeplalam Anudeep Lalam
              Votes:
              76 Vote for this issue
              Watchers:
              89 Start watching this issue

                Dates

                Created:
                Updated: