[GRADLE-2023] Concurrent Modification Exception during 'gradle tasks' Created: 03/Jan/12  Updated: 16/Jan/13  Resolved: 07/Jan/13

Status: Resolved
Project: Gradle
Affects Version/s: 1.0-milestone-6
Fix Version/s: 1.4-rc-1

Type: Bug
Reporter: Gradle Forums Assignee: Luke Daley
Resolution: Fixed Votes: 13

Attachments: File GradleDynamicTaskTest.zip    

 Description   

This problem appears in Gradle 1.0 milestone 6. It appears to come from the Cobertura plugin. I've made an effort to identify the origin of the problem, but my build is pretty big and I'm new to Gradle.

========== From my console: ===========

[spina:~/Code/apt/StagingGround] spina% gradle tasks --stacktrace
The SourceSet.getClassesDir() method is deprecated and will be removed in the next version of Gradle. You should use the getOutput().getClassesDir() method instead.
Disabling CosiMapJUnitTest. Failing because of GC behavior...
The SourceSet.getClasses() method is deprecated and will be removed in the next version of Gradle. You should use the getOutput() method instead.
:tasks

------------------------------------------------------------
All tasks runnable from root project
------------------------------------------------------------

FAILURE: Build failed with an exception.

  • What went wrong:
    Execution failed for task ':tasks'.
    Cause: java.util.ConcurrentModificationException (no error message)
  • Try:
    Run with --info or --debug option to get more log output.
  • Exception is:
    org.gradle.api.tasks.TaskExecutionException: Execution failed for task ':tasks'.
    at org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter.executeActions(ExecuteActionsTaskExecuter.java:71)
    at org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter.execute(ExecuteActionsTaskExecuter.java:48)
    at org.gradle.api.internal.tasks.execution.PostExecutionAnalysisTaskExecuter.execute(PostExecutionAnalysisTaskExecuter.java:34)
    at org.gradle.api.internal.tasks.execution.SkipUpToDateTaskExecuter.execute(SkipUpToDateTaskExecuter.java:55)
    at org.gradle.api.internal.tasks.execution.ValidatingTaskExecuter.execute(ValidatingTaskExecuter.java:57)
    at org.gradle.api.internal.tasks.execution.SkipEmptySourceFilesTaskExecuter.execute(SkipEmptySourceFilesTaskExecuter.java:41)
    at org.gradle.api.internal.tasks.execution.SkipTaskWithNoActionsExecuter.execute(SkipTaskWithNoActionsExecuter.java:51)
    at org.gradle.api.internal.tasks.execution.SkipOnlyIfTaskExecuter.execute(SkipOnlyIfTaskExecuter.java:52)
    at org.gradle.api.internal.tasks.execution.ExecuteAtMostOnceTaskExecuter.execute(ExecuteAtMostOnceTaskExecuter.java:42)
    at org.gradle.api.internal.AbstractTask.executeWithoutThrowingTaskFailure(AbstractTask.java:243)
    at org.gradle.execution.DefaultTaskGraphExecuter.executeTask(DefaultTaskGraphExecuter.java:192)
    at org.gradle.execution.DefaultTaskGraphExecuter.doExecute(DefaultTaskGraphExecuter.java:177)
    at org.gradle.execution.DefaultTaskGraphExecuter.execute(DefaultTaskGraphExecuter.java:83)
    at org.gradle.execution.SelectedTaskExecutionAction.execute(SelectedTaskExecutionAction.java:36)
    at org.gradle.execution.DefaultBuildExecuter.execute(DefaultBuildExecuter.java:70)
    at org.gradle.execution.DefaultBuildExecuter.access$300(DefaultBuildExecuter.java:23)
    at org.gradle.execution.DefaultBuildExecuter$2.proceed(DefaultBuildExecuter.java:80)
    at org.gradle.execution.DryRunBuildExecutionAction.execute(DryRunBuildExecutionAction.java:32)
    at org.gradle.execution.DefaultBuildExecuter.execute(DefaultBuildExecuter.java:70)
    at org.gradle.execution.DefaultBuildExecuter.execute(DefaultBuildExecuter.java:63)
    at org.gradle.initialization.DefaultGradleLauncher.doBuildStages(DefaultGradleLauncher.java:157)
    at org.gradle.initialization.DefaultGradleLauncher.doBuild(DefaultGradleLauncher.java:112)
    at org.gradle.initialization.DefaultGradleLauncher.run(DefaultGradleLauncher.java:80)
    at org.gradle.launcher.cli.RunBuildAction.execute(RunBuildAction.java:42)
    at org.gradle.launcher.cli.RunBuildAction.execute(RunBuildAction.java:28)
    at org.gradle.launcher.exec.ExceptionReportingAction.execute(ExceptionReportingAction.java:32)
    at org.gradle.launcher.exec.ExceptionReportingAction.execute(ExceptionReportingAction.java:21)
    at org.gradle.launcher.cli.CommandLineActionFactory$WithLoggingAction.execute(CommandLineActionFactory.java:233)
    at org.gradle.launcher.cli.CommandLineActionFactory$WithLoggingAction.execute(CommandLineActionFactory.java:217)
    at org.gradle.launcher.Main.doAction(Main.java:48)
    at org.gradle.launcher.exec.EntryPoint$1.execute(EntryPoint.java:53)
    at org.gradle.launcher.exec.EntryPoint$1.execute(EntryPoint.java:51)
    at org.gradle.launcher.exec.Execution.execute(Execution.java:28)
    at org.gradle.launcher.exec.EntryPoint.run(EntryPoint.java:39)
    at org.gradle.launcher.Main.main(Main.java:39)
    at org.gradle.launcher.ProcessBootstrap.runNoExit(ProcessBootstrap.java:51)
    at org.gradle.launcher.ProcessBootstrap.run(ProcessBootstrap.java:33)
    at org.gradle.launcher.GradleMain.main(GradleMain.java:24)
    Caused by: java.util.ConcurrentModificationException
    at org.gradle.api.internal.DefaultDomainObjectCollection$IteratorImpl.next(DefaultDomainObjectCollection.java:313)
    at org.gradle.api.internal.GraphAggregator.group(GraphAggregator.java:33)
    at org.gradle.api.tasks.diagnostics.internal.SingleProjectTaskReportModel.build(SingleProjectTaskReportModel.java:61)
    at org.gradle.api.tasks.diagnostics.TaskReportTask.generate(TaskReportTask.java:67)
    at org.gradle.api.tasks.diagnostics.AbstractReportTask.generate(AbstractReportTask.java:67)
    at org.gradle.api.internal.BeanDynamicObject.invokeMethod(BeanDynamicObject.java:158)
    at org.gradle.api.internal.CompositeDynamicObject.invokeMethod(CompositeDynamicObject.java:93)
    at org.gradle.api.tasks.diagnostics.TaskReportTask_Decorated.invokeMethod(Unknown Source)
    at org.gradle.util.ReflectionUtil.invoke(ReflectionUtil.groovy:23)
    at org.gradle.api.internal.project.taskfactory.AnnotationProcessingTaskFactory$2.execute(AnnotationProcessingTaskFactory.java:129)
    at org.gradle.api.internal.project.taskfactory.AnnotationProcessingTaskFactory$2.execute(AnnotationProcessingTaskFactory.java:127)
    at org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter.executeActions(ExecuteActionsTaskExecuter.java:63)
    ... 37 more

================ END CONSOLE OUTPUT =================

This is my build file:

==== begin build.gradle ====

// The sonar plugin collects build metrics. Useful for quality assurance.
apply plugin: "sonar"

sonar {
project

{ // TODO once using gradle v 1.0 milestone 7, the dynamicAnalysis line won't be needed. dynamicAnalysis = "reuseReports" sourceEncoding = "UTF-8" }

}

// This allows all groovy projects to easily reference the same groovy jar for building.
groovy_jar = "../Libraries/groovy-all-1.7.3.jar"

//ant.importBuild 'build.xml'
dependsOnChildren()

allprojects {
repositories

{ mavenCentral() }

}

subprojects {

// The cobertura plugin doesn't come with gradle by default. This makes it available and applies it.
buildscript {
// using a variable to make wiki look cleaner
def githubBase = '[1]https://github.com/valkolovos/gradle_...'
apply from: "${githubBase}/gradle_cobertura/gradle_cobertura/1.0-rc4/coberturainit.gradle"
}

sonar {
project

{ coberturaReportPath = file("$reportsDir/cobertura/coverage.xml") // testReportPath = file("$reportsDir/tests/junitreports") dynamicAnalysis = "reuseReports" }

}

apply plugin:'java'
sourceCompatibility = 6

dependencies

{ testCompile 'junit:junit:4.4' }

test

{ // Make sure that tests are executed from the APT root. This make relative path lookup work. workingDir = new File(project.projectDir.getCanonicalPath() + "/../") // TODO this is temporary so we can skip tagged tests. systemProperties "apt.build.is.gradle": "true" systemProperties "stsci.skip.performance": "true" // TODO this should be toggled dynamically. systemProperties "stsci.skip.network.tests": "true" }

compileJava

{ // This makes it so that the class filed don't have debug information. // This is how our ant build used to work. options.debug = false }

// The ant build puts Manifests into the jar by importing a file.
// It's not a very Gradle-y way of doing things, but works for now
// Eventually it would be desirable to make these files in the build itself.
jar {
manifest {
// Not actually made by ANT— just a cheap way to reduce differences.
attributes("Ant-Version": "Apache Ant 1.8.2", "Created-By": "1.6.0_29-b11-402-10M3527 (Apple Inc.)")
def manifestLocation = "${project.name}/MANIFEST.MF"
if(new File(manifestLocation).exists())

{ logger.info(project.name + ".jar will have a MANIFEST copied from MANIFEST.MF in it's root dir.") from('MANIFEST.MF') }

else

{ logger.info(project.name + " doesn't have a MANIFEST.MF in it's root dir.") }

}
}

}
====end build.gradle====

If I comment out the following lines then 'gradle tasks' works again:

buildscript {
// using a variable to make wiki look cleaner
def githubBase = '[2]https://github.com/valkolovos/gradle_...'
apply from: "${githubBase}/gradle_cobertura/gradle_cobertura/1.0-rc4/coberturainit.gradle"
}
coberturaReportPath = file("$reportsDir/cobertura/coverage.xml")

I'm not sure how those lines are breaking my build.

Note to self, the problem entered my build during the following changeset (found using bisect):

The first bad revision is:
changeset: 13615:e28b6e3c2872
parent: 13609:2946d90d6cbc
user: spina
date: Thu Dec 22 17:09:16 2011 -0500
summary: PR 69384 - Gradle now runs Tina Tests (though some are skipped). Hooked up Cobertura (code coverage) and Sonar.
----------------------------------------------------------------------------------------
[1] https://github.com/valkolovos/gradle_cobertura/raw/master/ivy
[2] https://github.com/valkolovos/gradle_cobertura/raw/master/ivy



 Comments   
Comment by Gradle Forums [ 03/Jan/12 ]

I got a similar exception when trying to upgrade from milestone-3 to a milestone-7 snapshot. I'm also using the cobertura plugin and will try and see if that is the culprit for me aswell. (i did manage to build my projects but the tasks task bugs out).

Comment by Szczepan Faber [ 11/Jan/12 ]

We had a similar problem related to this: http://forums.gradle.org/gradle/topics/upgrading_from_m3_to_m5_causes_a_circular_task_dependency_to_appear

If it helps in debugging this problem, I have a feeling that it might be related to existing circular dependency and reasonably complicated multi-project build.

Comment by Detelin Yordanov [ 30/Jan/12 ]

Here is a simple build script which demonstrates the issue. I have observed that it happens only on subprojects but not on the root project.

Comment by Mike M. [ 24/Feb/12 ]

I can confirm this issue and that it seems to come from the com.orbitz.gradle.cobertura.CoberturaPlugin plugin. We have the error happen only on the root build but not on the individual subprojects (one of our subprojects uses cobertura).

When I comment out the cobertura plugin / task config, it works.

Comment by Warren Muller [ 08/Mar/12 ]

I have hit this issue creating dynamic tasks in a plugin. The dynamic tasks have dependencies on existing java tasks. The plugin is applied to certain sub-tasks. Interesting is that running 'gradle tasks' fails in the parent project but works in the sub-task where the plugin is applied.
Its also a bit random. There is obviously some sequence of events that causes it work sometimes but most times it fails. I don't use the CoberturaPlugin explicitly anywhere

Comment by Warren Muller [ 08/Mar/12 ]

i've isolated the line that causes the java.util.ConcurrentModificationException:
project.getAt(PLUGIN_EXTENSION_NAME).wsdlDescriptors.each { k,v ->
// lots of other code ...
project.tasks.add(name: "wsdl2Java${k.capitalize()}",type: JavaExec) {
description="Generates Java source for wsdl:${k}=${v.file}"
outputs.upToDateSpec = new org.gradle.api.specs.AndSpec()
outputs.files generatedWsdlDir
inputs.files project.configurations.compile, wsdlFile
main = mc
classpath = cp
args = ag
}
project.clean.dependsOn "cleanWsdl2Java${k.capitalize()}" //This is the line that causes the java.util.ConcurrentModificationException
project."compile${wsdlSrcSetName.capitalize()}Java".dependsOn "wsdl2Java${k.capitalize()}" // This line works
}
project.compileJava.dependsOn project."${wsdlSrcSetName}Classes" //This line works
...

Comment by Warren Muller [ 08/Mar/12 ]

I've resolved my error by creating a single cleanWsdl task and creating the clean.dependsOn cleanWsdl. The dynamic patter clean<Task> would have all executed the same thing so were redundant when I had more than 1 wsdl anyway. If I had designed it differently with a sourceSet for each wsdl then maybe it would have still occurred but that would be overkill for my purposes.

Comment by Glen Stampoultzis [ 08/May/12 ]

I was able to fix this by altering TaskReportTask.java to copy the tasks collection before passing it down to the subprojects. I'm not sure if this is the best way do it though.

diff --git a/subprojects/core/src/main/groovy/org/gradle/api/tasks/diagnostics/TaskReportTask.java b/subprojects/core/src/main/groovy/org/gradle/api/tasks/diagnostics/TaskReportTask.java
index 8fa2c2c..ee3ce1b 100644
--- a/subprojects/core/src/main/groovy/org/gradle/api/tasks/diagnostics/TaskReportTask.java
+++ b/subprojects/core/src/main/groovy/org/gradle/api/tasks/diagnostics/TaskReportTask.java
@@ -18,11 +18,13 @@ package org.gradle.api.tasks.diagnostics;
 import com.google.common.collect.Sets;
 import org.gradle.api.Project;
 import org.gradle.api.Rule;
+import org.gradle.api.Task;
 import org.gradle.api.internal.project.ProjectInternal;
 import org.gradle.api.internal.tasks.CommandLineOption;
 import org.gradle.api.tasks.diagnostics.internal.*;
 
 import java.io.IOException;
+import java.util.ArrayList;
 
 /**
  * <p>Displays a list of tasks in the project. An instance of this type is used when you execute the {@code tasks} task
@@ -64,7 +66,7 @@ public class TaskReportTask extends AbstractReportTask {
 
         for (Project subprojects : project.getSubprojects()) {
             SingleProjectTaskReportModel subprojectTaskModel = new SingleProjectTaskReportModel(taskDetailsFactory);
-            subprojectTaskModel.build(subprojects.getTasks());
+            subprojectTaskModel.build(new ArrayList<Task>(subprojects.getTasks()));
             aggregateModel.add(subprojectTaskModel);
         }
 
Comment by Stephane Gallès [ 26/Jun/12 ]

In gradle 1.0 RC3, same problem when trying to create a task with a dependency on 'uploadArchives' in a plugin

Comment by Marcin Zajaczkowski [ 09/Jul/12 ]

I started to have that exception every time with "gradle tasks" after upgrade from 1.0-milestone-9 to 1.0-final.

Comment by Justin Ryan [ 10/Jul/12 ]

I ran into this with 1.0 and while I don't know the fix, I have a work around that might help give insight. From a plugin's apply block I was running:

        project.clean.dependsOn(':cleanDistribute')

And getting the exception, I changed it to the following to get it working:

        project.tasks['clean'].dependsOn project.tasks['cleanDistribute']

There's a few things different there, and I don't remember exactly which change made it work. But I believe it was the use of a string in the dependsOn, which is the lazy loading of a depends. Lazy loading and ConcurrentModificationException seems to hang out at the same bars a lot, so I'd bet there's a connection.

Comment by Stephane Gallès [ 16/Jul/12 ]

Thanks Justin, your workaround works like a charm.

Indeed, I just had to modify the dependsOn parameter in the configuration closure :
The following code triggers a Concurrent Modification Exception :

project.tasks.add('foo') { dependsOn 'uploadArchives' } 

But this works :

project.tasks.add('foo') { dependsOn project.tasks['uploadArchives'] } 
Comment by Thomas Glaeser [ 19/Dec/12 ]

Still an issue with Gradle 1.3

Comment by Thomas Glaeser [ 19/Dec/12 ]

The workarounds mentioned above probably works in simple scenarious, but when applying a plugin that makes usage of task rules there is no way to control this from the script.

Comment by René Gröschke (Inactive) [ 20/Dec/12 ]

This is not caused by adding simple task actions during execution phase as I expected. I think its a problem on how we deal with task rules.

Comment by Michael Brand [ 16/Jan/13 ]

Is this issue resolved? I'm seeing something similar using task rules, but I'm still on version 1.2.

Does anyone know of a workaround for task rules that doesn't involve updating Gradle versions?

Comment by Thomas Glaeser [ 16/Jan/13 ]

This is fixed in upcoming Gradle 1.4. Meanwhile you might try the following workaround (should be configured in the root project):

allprojects {
    it.implicitTasks.matching { it.name == "tasks" }.all {
        doFirst {
            rootProject.allprojects.each {
                def seen = new HashSet()
                while (seen != it.tasks) {
                    new HashSet(it.tasks).each {
                        it.getTaskDependencies().getDependencies(it)
                        seen << it
                    }
                }
            }
        }
    }
}
Comment by Michael Brand [ 16/Jan/13 ]

That worked! Thanks for the quick response.

Generated at Wed Jun 30 12:10:41 CDT 2021 using Jira 8.4.2#804003-sha1:d21414fc212e3af190e92c2d2ac41299b89402cf.