gradle-versions-plugin icon indicating copy to clipboard operation
gradle-versions-plugin copied to clipboard

dependencyUpdates task fails with ConcurrentModificationException since 0.52.0 in certain projects

Open mitchellmebane opened this issue 11 months ago • 32 comments

I am getting a ConcurrentModificationException when running the dependencyUpdates task in some of my Spring Boot projects after upgrading them to gradle-versions-plugin v0.52.0. After some experimentation, I've narrowed it down to projects which use all 3 of these plugins:

  • io.spring.dependency-management, any version since at least v3.1.0
  • info.solidsoft.pitest v1.15.0
  • com.github.ben-manes.versions v0.52.0

The relevant bit of the stack trace (I can copy the whole thing here if you'd like):

org.gradle.api.tasks.TaskExecutionException: Execution failed for task ':dependencyUpdates'.
        at org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter.lambda$executeIfValid$1(ExecuteActionsTaskExecuter.java:130)
        at org.gradle.internal.Try$Failure.ifSuccessfulOrElse(Try.java:293)
        <snip>
Caused by: java.util.ConcurrentModificationException
        at org.gradle.api.internal.collections.FilteredElementSource$FilteringIterator.findNext(FilteredElementSource.java:115)
        at org.gradle.api.internal.collections.FilteredElementSource$FilteringIterator.next(FilteredElementSource.java:134)
        at org.gradle.api.internal.DefaultDomainObjectCollection$IteratorImpl.next(DefaultDomainObjectCollection.java:494)
        at com.github.benmanes.gradle.versions.updates.DependencyUpdates.resolveProjects(DependencyUpdates.kt:78)
        at com.github.benmanes.gradle.versions.updates.DependencyUpdates.run(DependencyUpdates.kt:46)
        at com.github.benmanes.gradle.versions.updates.DependencyUpdatesTask.dependencyUpdates(DependencyUpdatesTask.kt:140)
        at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:103)
        at org.gradle.internal.reflect.JavaMethod.invoke(JavaMethod.java:125)
        at org.gradle.api.internal.project.taskfactory.StandardTaskAction.doExecute(StandardTaskAction.java:58)
        <snip>

Crashing line: DependencyUpdates.kt:78

I have a minimal reproducer here: https://github.com/mitchellmebane/gradle-versions-plugin-crash/

This sounds like it might have been caused by the fix to #907, or perhaps that fix just moved the weak point into the loop in resolveProjects and changed the timing enough that my projects only hit it now.

I don't know much about Gradle internals, but I'll try and dig into this more if I have time.

mitchellmebane avatar Jan 27 '25 00:01 mitchellmebane

ugh, sorry to hear that @mitchellmebane. I think you're right that it is the same as #907 and simply shifted the problem to now impact you. I believe this is a Gradle bug and that you may need to open an issue with them. The logic of their custom collection is confusing with these lazy side-effects that invalidate the iterator. From what I could tell, that iterator was in their code so any fix would be internal rather than by a plugin, so I'm skeptical that we can give you a proper workaround.

ben-manes avatar Jan 27 '25 02:01 ben-manes

DependencyUpdates.kt:42-44

      val projectConfigs =
        project.allprojects
          .associateBy({ it }, { it.configurations.matching(filterConfigurations) })

That's the source of the data. Looks like the actual type of projectConfigs is Map<Project, NamedDomainObjectSet<Configuration>>. NamedDomainObjectSet is a subtype of DomainObjectCollection, about which the docs say:

DomainObjectCollection instances are not thread-safe and undefined behavior may result from the invocation of any method on a collection that is being mutated by another thread; this includes direct invocations, passing the collection to a method that might perform invocations, and using an existing iterator to examine the collection.

which probably explains the issue.

It might be possible to change resolveProjects to take projectConfigs as a Map<Project, DomainObjectCollection<Configuration>>, and then use DomainObjectCollection.all instead of the loop. However, it's not clear from the documentation if that method is fully asynchronous, synchronous-for-things-currently-in-the-collection-and-then-async, or what. I'll do some more digging.

mitchellmebane avatar Jan 27 '25 05:01 mitchellmebane

I was thinking that the realizePending was adding to the collection, which invalidated any existing iterators by incrementing the mod count. This wouldn’t be a threading issue, but that modifications must go through the iterator in typical collections. Java’s concurrent collections use weakly consistent iterators, but non-concurrent throw CME for misuse rather than concurrency. That was my assumption last time I looked, but your rationale is interesting too. At execution time I didn’t expect this to be modified, only at init/configuration build phases.

ben-manes avatar Jan 27 '25 05:01 ben-manes

I was thinking that the realizePending was adding to the collection

Hm, that might be possible. I don't have a good feel for how all the lazy initialization works in Gradle yet.

This wouldn’t be a threading issue

Right, that would be a reentrancy issue. I guess I tend to conflate them in my mind. The good news is that if it's not caused by multi-threading, I can probably write a deterministic test case, if I can find what behavior is triggering the crash.

At execution time I didn’t expect this to be modified, only at init/configuration build phases.

Yes, that's definitely what I would expect after reading the Build Lifecycle documentation. I'm going to dig through the other two plugins in my repro project and see if they're modifying the configurations anywhere weird.

mitchellmebane avatar Jan 27 '25 15:01 mitchellmebane

Based on some simple print debugging, it looks like the runtime type of currentConfigurations is org.gradle.api.internal.DefaultNamedDomainObjectSet_Decorated.

DefaultNamedDomainObjectSet's iterator() implementation is DefaultDomainObjectCollection#iterator, which mostly just delegates to the backing store, which at runtime is FilteredElementSource#iterator. That implementation calls realizePending before starting iteration, which makes me think something else is modifying the configurations later, during the iteration - but I'm still learning most of this as I go, so 🤷.

I'll have to set up a real debugger tonight and look more closely.

mitchellmebane avatar Jan 27 '25 18:01 mitchellmebane

It has been a while since I attached a debugger directly to Gradle, but here are my notes.

In some cases the tasks accept --debug-jvm. Unfortunately I think this is only for test tasks to do the bootstrap for you.

More generally, for any Java program, you can use a remote attachment. In my projects, before that flag above, I used to use

if ("debug" in systemProperties) {
  jvmArgs("-Xdebug", "-Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=5005")
}

IntelliJ may have this built in now and it can all be done directly and understands their kts support. When I first wrote this plugin in groovy on gradle 1.0, IntelliJ had no support and Eclipse's was vastly superior thanks to Spring's plugin. At that time, when print debugging was not enough, I was able to step through this way (I think this was to pinpoint a bug in their repository handler that dropped maven repos by incorrect deduplication). hope this helps.

ben-manes avatar Jan 27 '25 19:01 ben-manes

IntelliJ is much smarter about this today indeed. I created a separate composite build with my repro project and the plugin project, imported it into IntelliJ, and can set breakpoints in the plugin while starting a debug of the dependencyUpdates task in the repro, and it all just works.

And there is, in fact, a modification of the configurations set during processing. When processing the testCompileClasspath configuration, this line triggers the addition of a tmpTestImplementation configuration:

Resolver.kt:279:

val lenient = copy.resolvedConfiguration.lenientConfiguration

That tmpTestImplemenation configuration is being added in gradle-pitest-plugin: PitestPlugin.groovy:267

Here's the call stack when that line is hit:

Stack Trace
doCall$original:267, PitestPlugin$_addJUnitPlatformLauncherDependencyIfNeeded_closure12$_closure16 (info.solidsoft.gradle.pitest)
doCall:-1, PitestPlugin$_addJUnitPlatformLauncherDependencyIfNeeded_closure12$_closure16 (info.solidsoft.gradle.pitest)
invokeSpecial:-1, DirectMethodHandle$Holder (java.lang.invoke)
invoke:-1, LambdaForm$MH/0x000000fc01098000 (java.lang.invoke)
invokeExact_MT:-1, Invokers$Holder (java.lang.invoke)
invokeImpl:154, DirectMethodHandleAccessor (jdk.internal.reflect)
invoke:103, DirectMethodHandleAccessor (jdk.internal.reflect)
invoke:580, Method (java.lang.reflect)
invoke:107, CachedMethod (org.codehaus.groovy.reflection)
doMethodInvoke:323, MetaMethod (groovy.lang)
invokeMethod:274, ClosureMetaClass (org.codehaus.groovy.runtime.metaclass)
invokeMethod:1030, MetaClassImpl (groovy.lang)
call:427, Closure (groovy.lang)
invokeCustom:50, ConvertedClosure (org.codehaus.groovy.runtime)
invoke:112, ConversionHandler (org.codehaus.groovy.runtime)
execute:-1, $Proxy124 (jdk.proxy1)
execute:285, ImmutableActionSet$SetWithFewActions (org.gradle.internal)
lambda$runDependencyActions$2:495, DefaultConfiguration (org.gradle.api.internal.artifacts.configurations)
execute:-1, DefaultConfiguration$$Lambda/0x000000fc016a79e8 (org.gradle.api.internal.artifacts.configurations)
runActionInHierarchy:1197, DefaultConfiguration (org.gradle.api.internal.artifacts.configurations)
runDependencyActions:493, DefaultConfiguration (org.gradle.api.internal.artifacts.configurations)
getDependencies:1906, DefaultConfiguration$ConfigurationResolvableDependencies (org.gradle.api.internal.artifacts.configurations)
getDependencies:-1, DefaultConfiguration$ConfigurationResolvableDependencies_Decorated (org.gradle.api.internal.artifacts.configurations)
getVersionedModuleDependencies:83, ImplicitDependencyManagementCollector (io.spring.gradle.dependencymanagement.internal)
processConfiguration:67, ImplicitDependencyManagementCollector (io.spring.gradle.dependencymanagement.internal)
accept:-1, ImplicitDependencyManagementCollector$$Lambda/0x000000fc01d6d7a0 (io.spring.gradle.dependencymanagement.internal)
forEach:75, Iterable (java.lang)
lambda$execute$0:61, ImplicitDependencyManagementCollector (io.spring.gradle.dependencymanagement.internal)
execute:-1, ImplicitDependencyManagementCollector$$Lambda/0x000000fc01cf9b78 (io.spring.gradle.dependencymanagement.internal)
execute:124, DefaultUserCodeApplicationContext$CurrentApplication$1 (org.gradle.internal.code)
dispatch:99, BroadcastDispatch$ActionInvocationHandler (org.gradle.internal.event)
dispatch:87, BroadcastDispatch$ActionInvocationHandler (org.gradle.internal.event)
dispatch:44, AbstractBroadcastDispatch (org.gradle.internal.event)
dispatch:268, BroadcastDispatch$SingletonDispatch (org.gradle.internal.event)
dispatch:170, BroadcastDispatch$SingletonDispatch (org.gradle.internal.event)
dispatch:84, AbstractBroadcastDispatch (org.gradle.internal.event)
dispatch:70, AbstractBroadcastDispatch (org.gradle.internal.event)
dispatch:380, BroadcastDispatch$CompositeDispatch (org.gradle.internal.event)
dispatch:272, BroadcastDispatch$CompositeDispatch (org.gradle.internal.event)
dispatch:153, ListenerBroadcast (org.gradle.internal.event)
dispatch:38, ListenerBroadcast (org.gradle.internal.event)
invoke:92, ProxyDispatchAdapter$DispatchingInvocationHandler (org.gradle.internal.dispatch)
beforeResolve:-1, $Proxy65 (jdk.proxy1)
runBeforeResolve:912, DefaultConfiguration (org.gradle.api.internal.artifacts.configurations)
access$1300:159, DefaultConfiguration (org.gradle.api.internal.artifacts.configurations)
call:781, DefaultConfiguration$1 (org.gradle.api.internal.artifacts.configurations)
call:777, DefaultConfiguration$1 (org.gradle.api.internal.artifacts.configurations)
execute:209, DefaultBuildOperationRunner$CallableBuildOperationWorker (org.gradle.internal.operations)
execute:204, DefaultBuildOperationRunner$CallableBuildOperationWorker (org.gradle.internal.operations)
execute:66, DefaultBuildOperationRunner$2 (org.gradle.internal.operations)
execute:59, DefaultBuildOperationRunner$2 (org.gradle.internal.operations)
execute:166, DefaultBuildOperationRunner (org.gradle.internal.operations)
execute:59, DefaultBuildOperationRunner (org.gradle.internal.operations)
call:53, DefaultBuildOperationRunner (org.gradle.internal.operations)
resolveGraphInBuildOperation:777, DefaultConfiguration (org.gradle.api.internal.artifacts.configurations)
lambda$resolveExclusivelyIfRequired$5:769, DefaultConfiguration (org.gradle.api.internal.artifacts.configurations)
apply:-1, DefaultConfiguration$$Lambda/0x000000fc016c55f8 (org.gradle.api.internal.artifacts.configurations)
update:509, DefaultProjectStateRegistry$CalculatedModelValueImpl (org.gradle.api.internal.project)
resolveExclusivelyIfRequired:764, DefaultConfiguration (org.gradle.api.internal.artifacts.configurations)
resolveGraphIfRequired:757, DefaultConfiguration (org.gradle.api.internal.artifacts.configurations)
access$1200:159, DefaultConfiguration (org.gradle.api.internal.artifacts.configurations)
getValue:731, DefaultConfiguration$ResolverResultsResolutionResultProvider (org.gradle.api.internal.artifacts.configurations)
getValue:692, DefaultConfiguration$ResolverResultsResolutionResultProvider (org.gradle.api.internal.artifacts.configurations)
getResolvedConfiguration:646, DefaultConfiguration (org.gradle.api.internal.artifacts.configurations)
getResolvedConfiguration:-1, DefaultUnlockedConfiguration_Decorated (org.gradle.api.internal.artifacts.configurations)
getCurrentCoordinates:279, Resolver (com.github.benmanes.gradle.versions.updates)
resolve:56, Resolver (com.github.benmanes.gradle.versions.updates)
resolve:101, DependencyUpdates (com.github.benmanes.gradle.versions.updates)
lambda 'forEach' in 'resolveProjects':86, DependencyUpdates (com.github.benmanes.gradle.versions.updates)
forEach:215, DependencyUpdates (com.github.benmanes.gradle.versions.updates)
resolveProjects:79, DependencyUpdates (com.github.benmanes.gradle.versions.updates)
run:49, DependencyUpdates (com.github.benmanes.gradle.versions.updates)
dependencyUpdates:140, DependencyUpdatesTask (com.github.benmanes.gradle.versions.updates)
invokeSpecial:-1, DirectMethodHandle$Holder (java.lang.invoke)
invoke:-1, LambdaForm$MH/0x000000fc01220800 (java.lang.invoke)
invokeExact_MT:-1, Invokers$Holder (java.lang.invoke)
invokeImpl:153, DirectMethodHandleAccessor (jdk.internal.reflect)
invoke:103, DirectMethodHandleAccessor (jdk.internal.reflect)
invoke:580, Method (java.lang.reflect)
invoke:125, JavaMethod (org.gradle.internal.reflect)
doExecute:58, StandardTaskAction (org.gradle.api.internal.project.taskfactory)
execute:51, StandardTaskAction (org.gradle.api.internal.project.taskfactory)
execute:29, StandardTaskAction (org.gradle.api.internal.project.taskfactory)
run:244, TaskExecution$3 (org.gradle.api.internal.tasks.execution)
execute:29, DefaultBuildOperationRunner$1 (org.gradle.internal.operations)
execute:26, DefaultBuildOperationRunner$1 (org.gradle.internal.operations)
execute:66, DefaultBuildOperationRunner$2 (org.gradle.internal.operations)
execute:59, DefaultBuildOperationRunner$2 (org.gradle.internal.operations)
execute:166, DefaultBuildOperationRunner (org.gradle.internal.operations)
execute:59, DefaultBuildOperationRunner (org.gradle.internal.operations)
run:47, DefaultBuildOperationRunner (org.gradle.internal.operations)
executeAction:229, TaskExecution (org.gradle.api.internal.tasks.execution)
executeActions:212, TaskExecution (org.gradle.api.internal.tasks.execution)
executeWithPreviousOutputFiles:195, TaskExecution (org.gradle.api.internal.tasks.execution)
execute:162, TaskExecution (org.gradle.api.internal.tasks.execution)
executeInternal:105, ExecuteStep (org.gradle.internal.execution.steps)
access$000:44, ExecuteStep (org.gradle.internal.execution.steps)
call:59, ExecuteStep$1 (org.gradle.internal.execution.steps)
call:56, ExecuteStep$1 (org.gradle.internal.execution.steps)
execute:209, DefaultBuildOperationRunner$CallableBuildOperationWorker (org.gradle.internal.operations)
execute:204, DefaultBuildOperationRunner$CallableBuildOperationWorker (org.gradle.internal.operations)
execute:66, DefaultBuildOperationRunner$2 (org.gradle.internal.operations)
execute:59, DefaultBuildOperationRunner$2 (org.gradle.internal.operations)
execute:166, DefaultBuildOperationRunner (org.gradle.internal.operations)
execute:59, DefaultBuildOperationRunner (org.gradle.internal.operations)
call:53, DefaultBuildOperationRunner (org.gradle.internal.operations)
execute:56, ExecuteStep (org.gradle.internal.execution.steps)
execute:44, ExecuteStep (org.gradle.internal.execution.steps)
execute:42, CancelExecutionStep (org.gradle.internal.execution.steps)
executeWithoutTimeout:75, TimeoutStep (org.gradle.internal.execution.steps)
execute:55, TimeoutStep (org.gradle.internal.execution.steps)
execute:50, PreCreateOutputParentsStep (org.gradle.internal.execution.steps)
execute:28, PreCreateOutputParentsStep (org.gradle.internal.execution.steps)
execute:67, RemovePreviousOutputsStep (org.gradle.internal.execution.steps)
execute:37, RemovePreviousOutputsStep (org.gradle.internal.execution.steps)
execute:61, BroadcastChangingOutputsStep (org.gradle.internal.execution.steps)
execute:26, BroadcastChangingOutputsStep (org.gradle.internal.execution.steps)
execute:69, CaptureOutputsAfterExecutionStep (org.gradle.internal.execution.steps)
execute:46, CaptureOutputsAfterExecutionStep (org.gradle.internal.execution.steps)
execute:40, ResolveInputChangesStep (org.gradle.internal.execution.steps)
execute:29, ResolveInputChangesStep (org.gradle.internal.execution.steps)
executeWithoutCache:189, BuildCacheStep (org.gradle.internal.execution.steps)
lambda$execute$1:75, BuildCacheStep (org.gradle.internal.execution.steps)
apply:-1, BuildCacheStep$$Lambda/0x000000fc01d63a10 (org.gradle.internal.execution.steps)
fold:175, Either$Right (org.gradle.internal)
fold:62, CachingState (org.gradle.internal.execution.caching)
execute:73, BuildCacheStep (org.gradle.internal.execution.steps)
execute:48, BuildCacheStep (org.gradle.internal.execution.steps)
execute:46, StoreExecutionStateStep (org.gradle.internal.execution.steps)
execute:35, StoreExecutionStateStep (org.gradle.internal.execution.steps)
executeBecause:75, SkipUpToDateStep (org.gradle.internal.execution.steps)
lambda$execute$2:53, SkipUpToDateStep (org.gradle.internal.execution.steps)
get:-1, SkipUpToDateStep$$Lambda/0x000000fc01cdd598 (org.gradle.internal.execution.steps)
orElseGet:364, Optional (java.util)
execute:53, SkipUpToDateStep (org.gradle.internal.execution.steps)
execute:35, SkipUpToDateStep (org.gradle.internal.execution.steps)
execute:37, MarkSnapshottingInputsFinishedStep (org.gradle.internal.execution.steps.legacy)
execute:27, MarkSnapshottingInputsFinishedStep (org.gradle.internal.execution.steps.legacy)
executeDelegate:49, ResolveIncrementalCachingStateStep (org.gradle.internal.execution.steps)
executeDelegate:27, ResolveIncrementalCachingStateStep (org.gradle.internal.execution.steps)
execute:71, AbstractResolveCachingStateStep (org.gradle.internal.execution.steps)
execute:39, AbstractResolveCachingStateStep (org.gradle.internal.execution.steps)
execute:65, ResolveChangesStep (org.gradle.internal.execution.steps)
execute:36, ResolveChangesStep (org.gradle.internal.execution.steps)
execute:107, ValidateStep (org.gradle.internal.execution.steps)
execute:56, ValidateStep (org.gradle.internal.execution.steps)
execute:64, AbstractCaptureStateBeforeExecutionStep (org.gradle.internal.execution.steps)
execute:43, AbstractCaptureStateBeforeExecutionStep (org.gradle.internal.execution.steps)
executeWithNonEmptySources:125, AbstractSkipEmptyWorkStep (org.gradle.internal.execution.steps)
execute:56, AbstractSkipEmptyWorkStep (org.gradle.internal.execution.steps)
execute:36, AbstractSkipEmptyWorkStep (org.gradle.internal.execution.steps)
execute:38, MarkSnapshottingInputsStartedStep (org.gradle.internal.execution.steps.legacy)
execute:36, LoadPreviousExecutionStateStep (org.gradle.internal.execution.steps)
execute:23, LoadPreviousExecutionStateStep (org.gradle.internal.execution.steps)
execute:75, HandleStaleOutputsStep (org.gradle.internal.execution.steps)
execute:41, HandleStaleOutputsStep (org.gradle.internal.execution.steps)
lambda$execute$0:35, AssignMutableWorkspaceStep (org.gradle.internal.execution.steps)
executeInWorkspace:-1, AssignMutableWorkspaceStep$$Lambda/0x000000fc01cbb698 (org.gradle.internal.execution.steps)
withWorkspace:289, TaskExecution$4 (org.gradle.api.internal.tasks.execution)
execute:31, AssignMutableWorkspaceStep (org.gradle.internal.execution.steps)
execute:22, AssignMutableWorkspaceStep (org.gradle.internal.execution.steps)
execute:40, ChoosePipelineStep (org.gradle.internal.execution.steps)
execute:23, ChoosePipelineStep (org.gradle.internal.execution.steps)
lambda$execute$2:67, ExecuteWorkBuildOperationFiringStep (org.gradle.internal.execution.steps)
get:-1, ExecuteWorkBuildOperationFiringStep$$Lambda/0x000000fc014ddb30 (org.gradle.internal.execution.steps)
orElseGet:364, Optional (java.util)
execute:67, ExecuteWorkBuildOperationFiringStep (org.gradle.internal.execution.steps)
execute:39, ExecuteWorkBuildOperationFiringStep (org.gradle.internal.execution.steps)
execute:46, IdentityCacheStep (org.gradle.internal.execution.steps)
execute:34, IdentityCacheStep (org.gradle.internal.execution.steps)
execute:48, IdentifyStep (org.gradle.internal.execution.steps)
execute:35, IdentifyStep (org.gradle.internal.execution.steps)
execute:61, DefaultExecutionEngine$1 (org.gradle.internal.execution.impl)
executeIfValid:127, ExecuteActionsTaskExecuter (org.gradle.api.internal.tasks.execution)
execute:116, ExecuteActionsTaskExecuter (org.gradle.api.internal.tasks.execution)
execute:46, FinalizePropertiesTaskExecuter (org.gradle.api.internal.tasks.execution)
execute:51, ResolveTaskExecutionModeExecuter (org.gradle.api.internal.tasks.execution)
execute:57, SkipTaskWithNoActionsExecuter (org.gradle.api.internal.tasks.execution)
execute:74, SkipOnlyIfTaskExecuter (org.gradle.api.internal.tasks.execution)
execute:36, CatchExceptionTaskExecuter (org.gradle.api.internal.tasks.execution)
executeTask:77, EventFiringTaskExecuter$1 (org.gradle.api.internal.tasks.execution)
call:55, EventFiringTaskExecuter$1 (org.gradle.api.internal.tasks.execution)
call:52, EventFiringTaskExecuter$1 (org.gradle.api.internal.tasks.execution)
execute:209, DefaultBuildOperationRunner$CallableBuildOperationWorker (org.gradle.internal.operations)
execute:204, DefaultBuildOperationRunner$CallableBuildOperationWorker (org.gradle.internal.operations)
execute:66, DefaultBuildOperationRunner$2 (org.gradle.internal.operations)
execute:59, DefaultBuildOperationRunner$2 (org.gradle.internal.operations)
execute:166, DefaultBuildOperationRunner (org.gradle.internal.operations)
execute:59, DefaultBuildOperationRunner (org.gradle.internal.operations)
call:53, DefaultBuildOperationRunner (org.gradle.internal.operations)
execute:52, EventFiringTaskExecuter (org.gradle.api.internal.tasks.execution)
execute:42, LocalTaskNodeExecutor (org.gradle.execution.plan)
execute:331, DefaultTaskExecutionGraph$InvokeNodeExecutorsAction (org.gradle.execution.taskgraph)
execute:318, DefaultTaskExecutionGraph$InvokeNodeExecutorsAction (org.gradle.execution.taskgraph)
lambda$execute$0:314, DefaultTaskExecutionGraph$BuildOperationAwareExecutionAction (org.gradle.execution.taskgraph)
run:-1, DefaultTaskExecutionGraph$BuildOperationAwareExecutionAction$$Lambda/0x000000fc01c93000 (org.gradle.execution.taskgraph)
with:85, CurrentBuildOperationRef (org.gradle.internal.operations)
execute:314, DefaultTaskExecutionGraph$BuildOperationAwareExecutionAction (org.gradle.execution.taskgraph)
execute:303, DefaultTaskExecutionGraph$BuildOperationAwareExecutionAction (org.gradle.execution.taskgraph)
execute:459, DefaultPlanExecutor$ExecutorWorker (org.gradle.execution.plan)
run:376, DefaultPlanExecutor$ExecutorWorker (org.gradle.execution.plan)
onExecute:64, ExecutorPolicy$CatchAndRecordFailures (org.gradle.internal.concurrent)
run:48, AbstractManagedExecutor$1 (org.gradle.internal.concurrent)
runWorker:1144, ThreadPoolExecutor (java.util.concurrent)
run:642, ThreadPoolExecutor$Worker (java.util.concurrent)
runWith:1588, Thread (java.lang)
run:1575, Thread (java.lang)

You can see the execution flows through the io.spring.dependency-management plugin. And if I remove that plugin from my project, that configuration in the pitest plugin doesn't run and the tmpTestImplementation configuration is not added.

I guess I'll have to look at the io.spring.dependency-management plugin next.

mitchellmebane avatar Jan 28 '25 05:01 mitchellmebane

It seems odd that they would add a configuration during dependency resolution? The withDependencies would be invoked when that configuration is being resolved, which then adds another configuration with more dependencies to the project. I could understand if it was a detached configuration, but here it is added to the project's configuration container at execution time which is invalid. If they are trying to resolve the configuration, then how we do it would make more sense? They modify the test configuration by adding a dependency to it, which may by chance be done before it was resolved since that likely depends on the testImplementation being evaluated. It seems like a very weird hack to me to implicitly add a dependency when it would otherwise be explicit. It is a confusing approach which I think typically a default dependency would be more straightforward.

I know a little about the io.spring.dependency-management as it handles BOM management. There was previously an issue with their resolution strategy not allowing us to query for dynamic versions. They were very responsive, helpful, and quickly resolved their issues.

I would guess that the spring plugin is adding the junit dependency via its BOM, and that triggers pitest to do this crazy logic.

ben-manes avatar Jan 28 '25 05:01 ben-manes

I have this problem since upgrade to Gradle 9.0.

  • com.github.ben-manes.versions v0.52.0
  • quarkus 3.25.2

michavansantvoort avatar Aug 14 '25 08:08 michavansantvoort

9.0 works for me using —no-parallel but that build doesn’t use quarkus.

ben-manes avatar Aug 14 '25 08:08 ben-manes

I tried it, but this workaround does change the outcome.

gradlew dependencyUpdates --no-parallel

FAILURE: Build failed with an exception.

  • What went wrong: Execution failed for task ':dependencyUpdates'.

java.util.ConcurrentModificationException

michavansantvoort avatar Aug 14 '25 08:08 michavansantvoort

Previously you found it was gradle-pitest-plugin modifying the configuration at execution time in an unsafe manner. Was that resolved?

ben-manes avatar Aug 14 '25 08:08 ben-manes

Sorry, I think it was someone else. I only use dependencyUpdates. I don't use the pitest plugin (and I don't modify configs ;-))

michavansantvoort avatar Aug 14 '25 08:08 michavansantvoort

Oh sorry. Above the issue was found to be another plugin modifying the configurations set during processing, which breaks the Gradle apis. There isn’t a way for this plugin to work around that, the other plugin must not corrupt the build state.

ben-manes avatar Aug 14 '25 08:08 ben-manes

I'm also now facing this for a normal Android app, I've disabled nearly all possible plugins and out of idea to identify the root cause.

Tolriq avatar Aug 15 '25 11:08 Tolriq

can you add a breakpoint to see what configuration is being created at execution time? You can see in the PitestPlugin.groovy linked above that they create a configuration as a side effect of other configurations, which leads to this ConcurrentModificationException when Gradle's lazy resolving in its iterator mutates the set. That plugin is performing unsafe logic so you might have something doing similar. A breakpoint in Gradle should show you where the culprit is that added to the set.

ben-manes avatar Aug 15 '25 16:08 ben-manes

I can't get the composite working in Android Studio will try again next week.

Tolriq avatar Aug 16 '25 07:08 Tolriq

Just as an FYI I ran into this today on a multimodule project using Gradle 9.0.0 And AS Narwhal 4 Canary 2. The project has four modules, three of which use dependencyUpdates plugin. Interestingly out of the three modules, one works fine, and the other two consistently fail with the ConcurrencyModificationException.

Unfortunately I've been away from this project, and did a bunch of version upgrading to it the last couple days,so I have no idea what change I made that is hitting this now. It use to work fine on all three modules until recent changes.

If there is something I can do to provide a diagnostic, lemme know.

The top of the call stack looks like this, it's the same stack as the original post above had:

Caused by: java.util.ConcurrentModificationException
	at org.gradle.api.internal.collections.FilteredElementSource$FilteringIterator.findNext(FilteredElementSource.java:115)
	at org.gradle.api.internal.collections.FilteredElementSource$FilteringIterator.next(FilteredElementSource.java:134)
	at org.gradle.api.internal.DefaultDomainObjectCollection$IteratorImpl.next(DefaultDomainObjectCollection.java:494)
	at com.github.benmanes.gradle.versions.updates.DependencyUpdates.resolveProjects(DependencyUpdates.kt:78)
	at com.github.benmanes.gradle.versions.updates.DependencyUpdates.run(DependencyUpdates.kt:46)
	at com.github.benmanes.gradle.versions.updates.DependencyUpdatesTask.dependencyUpdates(DependencyUpdatesTask.kt:140)
	at org.gradle.internal.reflect.JavaMethod.invoke(JavaMethod.java:125)
	at org.gradle.api.internal.project.taskfactory.StandardTaskAction.doExecute(StandardTaskAction.java:58)
	at org.gradle.api.internal.project.taskfactory.StandardTaskAction.execute(StandardTaskAction.java:51)
	at org.gradle.api.internal.project.taskfactory.StandardTaskAction.execute(StandardTaskAction.java:29)
	at org.gradle.api.internal.tasks.execution.TaskExecution$3.run(TaskExecution.java:252)

skolson avatar Aug 26 '25 00:08 skolson

I think you would either (a) need to attach a debugger to see what is adding to the configuration while its being resolved or (b) raise an issue with the Gradle team. I believe they would argue its a problem from (a) that needs to not modify add configurations during resolution because configurations are lazy now (were originally eager). However, they might be generous to say (b) for them to change their internal collection type be concurrent for a weakly consistent iterator. The problem is I can't help because the gradle-versions-plugin is merely using the Gradle public API and there isn't any real workaround. I think the best I could do is something ugly like catching and retrying a few times, which is fundamentally wrong since ConcurrentModificationException means the collection may be in an corrupted and unrecoverable state.

ben-manes avatar Aug 26 '25 00:08 ben-manes

Also facing the same issue currently.

@ben-manes @mitchellmebane I'd like to attach a debugger, but I can't get the composite build working, it I attach this plugin's source code root as my project's included build I got the following error:

FAILURE: Build failed with an exception.

* What went wrong:
org.gradle.api.internal.catalog.GeneratedClassCompilationException: Unable to compile generated sources:
  - File RootProjectAccessor.java, line: 29, method getGradleVersionsPlugin() is already defined in class org.gradle.accessors.dm.RootProjectAccessor
> Unable to compile generated sources:
    - File RootProjectAccessor.java, line: 29, method getGradleVersionsPlugin() is already defined in class org.gradle.accessors.dm.RootProjectAccessor

* Try:
> Run with --info or --debug option to get more log output.
> Run with --scan to generate a Build Scan (Powered by Develocity).
> Get more help at https://help.gradle.org.

* Exception is:
java.lang.RuntimeException: org.gradle.api.internal.catalog.GeneratedClassCompilationException: Unable to compile generated sources:
  - File RootProjectAccessor.java, line: 29, method getGradleVersionsPlugin() is already defined in class org.gradle.accessors.dm.RootProjectAccessor
        at org.gradle.api.internal.catalog.DefaultDependenciesAccessors.generateAccessors(DefaultDependenciesAccessors.java:162)
        at org.gradle.configuration.BuildTreePreparingProjectsPreparer.generateDependenciesAccessorsAndAssignPluginVersions(BuildTreePreparingProjectsPreparer.java:92)
        at org.gradle.configuration.BuildTreePreparingProjectsPreparer.prepareProjects(BuildTreePreparingProjectsPreparer.java:55)
        at org.gradle.configuration.BuildOperationFiringProjectsPreparer$ConfigureBuild.run(BuildOperationFiringProjectsPreparer.java:52)
        at org.gradle.internal.operations.DefaultBuildOperationRunner$1.execute(DefaultBuildOperationRunner.java:29)
        at org.gradle.internal.operations.DefaultBuildOperationRunner$1.execute(DefaultBuildOperationRunner.java:26)
        at org.gradle.internal.operations.DefaultBuildOperationRunner$2.execute(DefaultBuildOperationRunner.java:66)
        at org.gradle.internal.operations.DefaultBuildOperationRunner$2.execute(DefaultBuildOperationRunner.java:59)
        at org.gradle.internal.operations.DefaultBuildOperationRunner.execute(DefaultBuildOperationRunner.java:166)
        at org.gradle.internal.operations.DefaultBuildOperationRunner.execute(DefaultBuildOperationRunner.java:59)
        at org.gradle.internal.operations.DefaultBuildOperationRunner.run(DefaultBuildOperationRunner.java:47)
        at org.gradle.configuration.BuildOperationFiringProjectsPreparer.prepareProjects(BuildOperationFiringProjectsPreparer.java:40)
        at org.gradle.initialization.VintageBuildModelController.lambda$prepareProjects$2(VintageBuildModelController.java:83)
        at org.gradle.internal.model.StateTransitionController.lambda$doTransition$14(StateTransitionController.java:255)
        at org.gradle.internal.model.StateTransitionController.doTransition(StateTransitionController.java:266)
        at org.gradle.internal.model.StateTransitionController.doTransition(StateTransitionController.java:254)
        at org.gradle.internal.model.StateTransitionController.lambda$transitionIfNotPreviously$11(StateTransitionController.java:213)
        at org.gradle.internal.work.DefaultSynchronizer.withLock(DefaultSynchronizer.java:35)
        at org.gradle.internal.model.StateTransitionController.transitionIfNotPreviously(StateTransitionController.java:209)
        at org.gradle.initialization.VintageBuildModelController.prepareProjects(VintageBuildModelController.java:83)
        at org.gradle.initialization.VintageBuildModelController.getConfiguredModel(VintageBuildModelController.java:63)
        at org.gradle.internal.cc.impl.ConfigurationCacheAwareBuildModelController.getConfiguredModel(ConfigurationCacheAwareBuildModelController.kt:43)
        at org.gradle.internal.model.StateTransitionController.lambda$notInState$3(StateTransitionController.java:132)
        at org.gradle.internal.work.DefaultSynchronizer.withLock(DefaultSynchronizer.java:45)
        at org.gradle.internal.model.StateTransitionController.notInState(StateTransitionController.java:128)
        at org.gradle.internal.build.DefaultBuildLifecycleController.configureProjects(DefaultBuildLifecycleController.java:128)
        at org.gradle.internal.build.AbstractBuildState.ensureProjectsConfigured(AbstractBuildState.java:145)
        at org.gradle.composite.internal.AbstractCompositeParticipantBuildState.ensureChildBuildConfigured(AbstractCompositeParticipantBuildState.java:61)
        at org.gradle.composite.internal.AbstractCompositeParticipantBuildState.getAvailableModules(AbstractCompositeParticipantBuildState.java:51)
        at org.gradle.composite.internal.IncludedBuildDependencySubstitutionsBuilder.build(IncludedBuildDependencySubstitutionsBuilder.java:83)
        at org.gradle.composite.internal.IncludedBuildDependencySubstitutionsBuilder.registerSubstitutionsFor(IncludedBuildDependencySubstitutionsBuilder.java:64)
        at org.gradle.internal.buildtree.BuildInclusionCoordinator.lambda$registerSubstitutionsFor$1(BuildInclusionCoordinator.java:143)
        at org.gradle.internal.buildtree.BuildInclusionCoordinator$BuildSynchronizer.lambda$withLock$0(BuildInclusionCoordinator.java:66)
        at org.gradle.internal.work.DefaultSynchronizer.withLock(DefaultSynchronizer.java:35)
        at org.gradle.internal.buildtree.BuildInclusionCoordinator$BuildSynchronizer.withLock(BuildInclusionCoordinator.java:60)
        at org.gradle.internal.buildtree.BuildInclusionCoordinator.withLockForBuild(BuildInclusionCoordinator.java:147)
        at org.gradle.internal.buildtree.BuildInclusionCoordinator.registerSubstitutionsFor(BuildInclusionCoordinator.java:143)
        at org.gradle.internal.buildtree.BuildInclusionCoordinator.registerGlobalLibrarySubstitutions(BuildInclusionCoordinator.java:97)
        at org.gradle.internal.buildtree.BuildInclusionCoordinator.registerSubstitutionsAvailableFor(BuildInclusionCoordinator.java:103)
        at org.gradle.configuration.BuildTreePreparingProjectsPreparer.prepareProjects(BuildTreePreparingProjectsPreparer.java:60)
        at org.gradle.configuration.BuildOperationFiringProjectsPreparer$ConfigureBuild.run(BuildOperationFiringProjectsPreparer.java:52)
        at org.gradle.internal.operations.DefaultBuildOperationRunner$1.execute(DefaultBuildOperationRunner.java:29)
        at org.gradle.internal.operations.DefaultBuildOperationRunner$1.execute(DefaultBuildOperationRunner.java:26)
        at org.gradle.internal.operations.DefaultBuildOperationRunner$2.execute(DefaultBuildOperationRunner.java:66)
        at org.gradle.internal.operations.DefaultBuildOperationRunner$2.execute(DefaultBuildOperationRunner.java:59)
        at org.gradle.internal.operations.DefaultBuildOperationRunner.execute(DefaultBuildOperationRunner.java:166)
        at org.gradle.internal.operations.DefaultBuildOperationRunner.execute(DefaultBuildOperationRunner.java:59)
        at org.gradle.internal.operations.DefaultBuildOperationRunner.run(DefaultBuildOperationRunner.java:47)
        at org.gradle.configuration.BuildOperationFiringProjectsPreparer.prepareProjects(BuildOperationFiringProjectsPreparer.java:40)
        at org.gradle.initialization.VintageBuildModelController.lambda$prepareProjects$2(VintageBuildModelController.java:83)
        at org.gradle.internal.model.StateTransitionController.lambda$doTransition$14(StateTransitionController.java:255)
        at org.gradle.internal.model.StateTransitionController.doTransition(StateTransitionController.java:266)
        at org.gradle.internal.model.StateTransitionController.doTransition(StateTransitionController.java:254)
        at org.gradle.internal.model.StateTransitionController.lambda$transitionIfNotPreviously$11(StateTransitionController.java:213)
        at org.gradle.internal.work.DefaultSynchronizer.withLock(DefaultSynchronizer.java:35)
        at org.gradle.internal.model.StateTransitionController.transitionIfNotPreviously(StateTransitionController.java:209)
        at org.gradle.initialization.VintageBuildModelController.prepareProjects(VintageBuildModelController.java:83)
        at org.gradle.initialization.VintageBuildModelController.prepareToScheduleTasks(VintageBuildModelController.java:70)
        at org.gradle.internal.cc.impl.ConfigurationCacheAwareBuildModelController.prepareToScheduleTasks(ConfigurationCacheAwareBuildModelController.kt:49)
        at org.gradle.internal.build.DefaultBuildLifecycleController.lambda$prepareToScheduleTasks$6(DefaultBuildLifecycleController.java:175)
        at org.gradle.internal.model.StateTransitionController.lambda$doTransition$14(StateTransitionController.java:255)
        at org.gradle.internal.model.StateTransitionController.doTransition(StateTransitionController.java:266)
        at org.gradle.internal.model.StateTransitionController.doTransition(StateTransitionController.java:254)
        at org.gradle.internal.model.StateTransitionController.lambda$maybeTransition$9(StateTransitionController.java:190)
        at org.gradle.internal.work.DefaultSynchronizer.withLock(DefaultSynchronizer.java:35)
        at org.gradle.internal.model.StateTransitionController.maybeTransition(StateTransitionController.java:186)
        at org.gradle.internal.build.DefaultBuildLifecycleController.prepareToScheduleTasks(DefaultBuildLifecycleController.java:173)
        at org.gradle.internal.buildtree.DefaultBuildTreeWorkPreparer.scheduleRequestedTasks(DefaultBuildTreeWorkPreparer.java:35)
        at org.gradle.internal.cc.impl.ConfigurationCacheAwareBuildTreeWorkController$scheduleAndRunRequestedTasks$executionResult$1.apply$lambda$0(ConfigurationCacheAwareBuildTreeWorkController.kt:48)
        at org.gradle.internal.cc.impl.DefaultConfigurationCache.loadOrScheduleRequestedTasks$lambda$10(DefaultConfigurationCache.kt:245)
        at org.gradle.internal.cc.impl.DefaultConfigurationCache.runWorkThatContributesToCacheEntry(DefaultConfigurationCache.kt:576)
        at org.gradle.internal.cc.impl.DefaultConfigurationCache.loadOrScheduleRequestedTasks(DefaultConfigurationCache.kt:244)
        at org.gradle.internal.cc.impl.ConfigurationCacheAwareBuildTreeWorkController$scheduleAndRunRequestedTasks$executionResult$1.apply(ConfigurationCacheAwareBuildTreeWorkController.kt:45)
        at org.gradle.internal.cc.impl.ConfigurationCacheAwareBuildTreeWorkController$scheduleAndRunRequestedTasks$executionResult$1.apply(ConfigurationCacheAwareBuildTreeWorkController.kt:44)
        at org.gradle.composite.internal.DefaultIncludedBuildTaskGraph.withNewWorkGraph(DefaultIncludedBuildTaskGraph.java:113)
        at org.gradle.internal.cc.impl.ConfigurationCacheAwareBuildTreeWorkController.scheduleAndRunRequestedTasks(ConfigurationCacheAwareBuildTreeWorkController.kt:44)
        at org.gradle.internal.buildtree.DefaultBuildTreeLifecycleController.lambda$scheduleAndRunTasks$1(DefaultBuildTreeLifecycleController.java:77)
        at org.gradle.internal.buildtree.DefaultBuildTreeLifecycleController.lambda$runBuild$4(DefaultBuildTreeLifecycleController.java:120)
        at org.gradle.internal.model.StateTransitionController.lambda$transition$6(StateTransitionController.java:169)
        at org.gradle.internal.model.StateTransitionController.doTransition(StateTransitionController.java:266)
        at org.gradle.internal.model.StateTransitionController.lambda$transition$7(StateTransitionController.java:169)
        at org.gradle.internal.work.DefaultSynchronizer.withLock(DefaultSynchronizer.java:45)
        at org.gradle.internal.model.StateTransitionController.transition(StateTransitionController.java:169)
        at org.gradle.internal.buildtree.DefaultBuildTreeLifecycleController.runBuild(DefaultBuildTreeLifecycleController.java:117)
        at org.gradle.internal.buildtree.DefaultBuildTreeLifecycleController.scheduleAndRunTasks(DefaultBuildTreeLifecycleController.java:77)
        at org.gradle.internal.buildtree.DefaultBuildTreeLifecycleController.scheduleAndRunTasks(DefaultBuildTreeLifecycleController.java:72)
        at org.gradle.tooling.internal.provider.ExecuteBuildActionRunner.run(ExecuteBuildActionRunner.java:31)
        at org.gradle.launcher.exec.ChainingBuildActionRunner.run(ChainingBuildActionRunner.java:35)
        at org.gradle.internal.buildtree.ProblemReportingBuildActionRunner.run(ProblemReportingBuildActionRunner.java:54)
        at org.gradle.launcher.exec.BuildOutcomeReportingBuildActionRunner.run(BuildOutcomeReportingBuildActionRunner.java:83)
        at org.gradle.tooling.internal.provider.FileSystemWatchingBuildActionRunner.run(FileSystemWatchingBuildActionRunner.java:135)
        at org.gradle.launcher.exec.BuildCompletionNotifyingBuildActionRunner.run(BuildCompletionNotifyingBuildActionRunner.java:54)
        at org.gradle.launcher.exec.RootBuildLifecycleBuildActionExecutor.lambda$execute$0(RootBuildLifecycleBuildActionExecutor.java:56)
        at org.gradle.composite.internal.DefaultRootBuildState.run(DefaultRootBuildState.java:130)
        at org.gradle.launcher.exec.RootBuildLifecycleBuildActionExecutor.execute(RootBuildLifecycleBuildActionExecutor.java:56)
        at org.gradle.internal.buildtree.InitDeprecationLoggingActionExecutor.execute(InitDeprecationLoggingActionExecutor.java:62)
        at org.gradle.internal.buildtree.InitProblems.execute(InitProblems.java:36)
        at org.gradle.internal.buildtree.DefaultBuildTreeContext.execute(DefaultBuildTreeContext.java:40)
        at org.gradle.launcher.exec.BuildTreeLifecycleBuildActionExecutor.lambda$execute$0(BuildTreeLifecycleBuildActionExecutor.java:71)
        at org.gradle.internal.buildtree.BuildTreeState.run(BuildTreeState.java:60)
        at org.gradle.launcher.exec.BuildTreeLifecycleBuildActionExecutor.execute(BuildTreeLifecycleBuildActionExecutor.java:71)
        at org.gradle.launcher.exec.RunAsBuildOperationBuildActionExecutor$2.call(RunAsBuildOperationBuildActionExecutor.java:65)
        at org.gradle.launcher.exec.RunAsBuildOperationBuildActionExecutor$2.call(RunAsBuildOperationBuildActionExecutor.java:61)
        at org.gradle.internal.operations.DefaultBuildOperationRunner$CallableBuildOperationWorker.execute(DefaultBuildOperationRunner.java:209)
        at org.gradle.internal.operations.DefaultBuildOperationRunner$CallableBuildOperationWorker.execute(DefaultBuildOperationRunner.java:204)
        at org.gradle.internal.operations.DefaultBuildOperationRunner$2.execute(DefaultBuildOperationRunner.java:66)
        at org.gradle.internal.operations.DefaultBuildOperationRunner$2.execute(DefaultBuildOperationRunner.java:59)
        at org.gradle.internal.operations.DefaultBuildOperationRunner.execute(DefaultBuildOperationRunner.java:166)
        at org.gradle.internal.operations.DefaultBuildOperationRunner.execute(DefaultBuildOperationRunner.java:59)
        at org.gradle.internal.operations.DefaultBuildOperationRunner.call(DefaultBuildOperationRunner.java:53)
        at org.gradle.launcher.exec.RunAsBuildOperationBuildActionExecutor.execute(RunAsBuildOperationBuildActionExecutor.java:61)
        at org.gradle.launcher.exec.RunAsWorkerThreadBuildActionExecutor.lambda$execute$0(RunAsWorkerThreadBuildActionExecutor.java:36)
        at org.gradle.internal.work.DefaultWorkerLeaseService.withLocks(DefaultWorkerLeaseService.java:263)
        at org.gradle.internal.work.DefaultWorkerLeaseService.runAsWorkerThread(DefaultWorkerLeaseService.java:127)
        at org.gradle.launcher.exec.RunAsWorkerThreadBuildActionExecutor.execute(RunAsWorkerThreadBuildActionExecutor.java:36)
        at org.gradle.tooling.internal.provider.continuous.ContinuousBuildActionExecutor.execute(ContinuousBuildActionExecutor.java:110)
        at org.gradle.tooling.internal.provider.SubscribableBuildActionExecutor.execute(SubscribableBuildActionExecutor.java:64)
        at org.gradle.internal.session.DefaultBuildSessionContext.execute(DefaultBuildSessionContext.java:46)
        at org.gradle.internal.buildprocess.execution.BuildSessionLifecycleBuildActionExecutor$ActionImpl.apply(BuildSessionLifecycleBuildActionExecutor.java:92)
        at org.gradle.internal.buildprocess.execution.BuildSessionLifecycleBuildActionExecutor$ActionImpl.apply(BuildSessionLifecycleBuildActionExecutor.java:80)
        at org.gradle.internal.session.BuildSessionState.run(BuildSessionState.java:73)
        at org.gradle.internal.buildprocess.execution.BuildSessionLifecycleBuildActionExecutor.execute(BuildSessionLifecycleBuildActionExecutor.java:62)
        at org.gradle.internal.buildprocess.execution.BuildSessionLifecycleBuildActionExecutor.execute(BuildSessionLifecycleBuildActionExecutor.java:41)
        at org.gradle.internal.buildprocess.execution.StartParamsValidatingActionExecutor.execute(StartParamsValidatingActionExecutor.java:57)
        at org.gradle.internal.buildprocess.execution.StartParamsValidatingActionExecutor.execute(StartParamsValidatingActionExecutor.java:32)
        at org.gradle.internal.buildprocess.execution.SessionFailureReportingActionExecutor.execute(SessionFailureReportingActionExecutor.java:51)
        at org.gradle.internal.buildprocess.execution.SessionFailureReportingActionExecutor.execute(SessionFailureReportingActionExecutor.java:39)
        at org.gradle.internal.buildprocess.execution.SetupLoggingActionExecutor.execute(SetupLoggingActionExecutor.java:47)
        at org.gradle.internal.buildprocess.execution.SetupLoggingActionExecutor.execute(SetupLoggingActionExecutor.java:31)
        at org.gradle.launcher.daemon.server.exec.ExecuteBuild.doBuild(ExecuteBuild.java:70)
        at org.gradle.launcher.daemon.server.exec.BuildCommandOnly.execute(BuildCommandOnly.java:37)
        at org.gradle.launcher.daemon.server.api.DaemonCommandExecution.proceed(DaemonCommandExecution.java:104)
        at org.gradle.launcher.daemon.server.exec.WatchForDisconnection.execute(WatchForDisconnection.java:39)
        at org.gradle.launcher.daemon.server.api.DaemonCommandExecution.proceed(DaemonCommandExecution.java:104)
        at org.gradle.launcher.daemon.server.exec.ResetDeprecationLogger.execute(ResetDeprecationLogger.java:29)
        at org.gradle.launcher.daemon.server.api.DaemonCommandExecution.proceed(DaemonCommandExecution.java:104)
        at org.gradle.launcher.daemon.server.exec.RequestStopIfSingleUsedDaemon.execute(RequestStopIfSingleUsedDaemon.java:35)
        at org.gradle.launcher.daemon.server.api.DaemonCommandExecution.proceed(DaemonCommandExecution.java:104)
        at org.gradle.launcher.daemon.server.exec.ForwardClientInput.lambda$execute$0(ForwardClientInput.java:40)
        at org.gradle.internal.daemon.clientinput.ClientInputForwarder.forwardInput(ClientInputForwarder.java:80)
        at org.gradle.launcher.daemon.server.exec.ForwardClientInput.execute(ForwardClientInput.java:37)
        at org.gradle.launcher.daemon.server.api.DaemonCommandExecution.proceed(DaemonCommandExecution.java:104)
        at org.gradle.launcher.daemon.server.exec.LogAndCheckHealth.execute(LogAndCheckHealth.java:64)
        at org.gradle.launcher.daemon.server.api.DaemonCommandExecution.proceed(DaemonCommandExecution.java:104)
        at org.gradle.launcher.daemon.server.exec.LogToClient.doBuild(LogToClient.java:63)
        at org.gradle.launcher.daemon.server.exec.BuildCommandOnly.execute(BuildCommandOnly.java:37)
        at org.gradle.launcher.daemon.server.api.DaemonCommandExecution.proceed(DaemonCommandExecution.java:104)
        at org.gradle.launcher.daemon.server.exec.EstablishBuildEnvironment.doBuild(EstablishBuildEnvironment.java:84)
        at org.gradle.launcher.daemon.server.exec.BuildCommandOnly.execute(BuildCommandOnly.java:37)
        at org.gradle.launcher.daemon.server.api.DaemonCommandExecution.proceed(DaemonCommandExecution.java:104)
        at org.gradle.launcher.daemon.server.exec.StartBuildOrRespondWithBusy$1.run(StartBuildOrRespondWithBusy.java:52)
        at org.gradle.launcher.daemon.server.DaemonStateCoordinator.lambda$runCommand$0(DaemonStateCoordinator.java:321)
        at org.gradle.internal.concurrent.ExecutorPolicy$CatchAndRecordFailures.onExecute(ExecutorPolicy.java:64)
        at org.gradle.internal.concurrent.AbstractManagedExecutor$1.run(AbstractManagedExecutor.java:47)
Caused by: org.gradle.api.internal.catalog.GeneratedClassCompilationException: Unable to compile generated sources:
  - File RootProjectAccessor.java, line: 29, method getGradleVersionsPlugin() is already defined in class org.gradle.accessors.dm.RootProjectAccessor
        at org.gradle.api.internal.catalog.SimpleGeneratedJavaClassCompiler.throwCompilationError(SimpleGeneratedJavaClassCompiler.java:82)
        at org.gradle.api.internal.catalog.SimpleGeneratedJavaClassCompiler.compile(SimpleGeneratedJavaClassCompiler.java:67)
        at org.gradle.api.internal.catalog.DefaultDependenciesAccessors$AbstractAccessorUnitOfWork.execute(DefaultDependenciesAccessors.java:367)
        at org.gradle.internal.execution.steps.ExecuteStep.executeInternal(ExecuteStep.java:105)
        at org.gradle.internal.execution.steps.ExecuteStep.access$000(ExecuteStep.java:44)
        at org.gradle.internal.execution.steps.ExecuteStep$1.call(ExecuteStep.java:59)
        at org.gradle.internal.execution.steps.ExecuteStep$1.call(ExecuteStep.java:56)
        at org.gradle.internal.operations.DefaultBuildOperationRunner$CallableBuildOperationWorker.execute(DefaultBuildOperationRunner.java:209)
        at org.gradle.internal.operations.DefaultBuildOperationRunner$CallableBuildOperationWorker.execute(DefaultBuildOperationRunner.java:204)
        at org.gradle.internal.operations.DefaultBuildOperationRunner$2.execute(DefaultBuildOperationRunner.java:66)
        at org.gradle.internal.operations.DefaultBuildOperationRunner$2.execute(DefaultBuildOperationRunner.java:59)
        at org.gradle.internal.operations.DefaultBuildOperationRunner.execute(DefaultBuildOperationRunner.java:166)
        at org.gradle.internal.operations.DefaultBuildOperationRunner.execute(DefaultBuildOperationRunner.java:59)
        at org.gradle.internal.operations.DefaultBuildOperationRunner.call(DefaultBuildOperationRunner.java:53)
        at org.gradle.internal.execution.steps.ExecuteStep.execute(ExecuteStep.java:56)
        at org.gradle.internal.execution.steps.ExecuteStep.execute(ExecuteStep.java:44)
        at org.gradle.internal.execution.steps.CancelExecutionStep.execute(CancelExecutionStep.java:42)
        at org.gradle.internal.execution.steps.TimeoutStep.executeWithoutTimeout(TimeoutStep.java:75)
        at org.gradle.internal.execution.steps.TimeoutStep.execute(TimeoutStep.java:55)
        at org.gradle.internal.execution.steps.PreCreateOutputParentsStep.execute(PreCreateOutputParentsStep.java:50)
        at org.gradle.internal.execution.steps.PreCreateOutputParentsStep.execute(PreCreateOutputParentsStep.java:28)
        at org.gradle.internal.execution.steps.BroadcastChangingOutputsStep.execute(BroadcastChangingOutputsStep.java:61)
        at org.gradle.internal.execution.steps.BroadcastChangingOutputsStep.execute(BroadcastChangingOutputsStep.java:26)
        at org.gradle.internal.execution.steps.NoInputChangesStep.execute(NoInputChangesStep.java:30)
        at org.gradle.internal.execution.steps.NoInputChangesStep.execute(NoInputChangesStep.java:21)
        at org.gradle.internal.execution.steps.CaptureOutputsAfterExecutionStep.execute(CaptureOutputsAfterExecutionStep.java:69)
        at org.gradle.internal.execution.steps.CaptureOutputsAfterExecutionStep.execute(CaptureOutputsAfterExecutionStep.java:46)
        at org.gradle.internal.execution.steps.BuildCacheStep.executeWithoutCache(BuildCacheStep.java:189)
        at org.gradle.internal.execution.steps.BuildCacheStep.lambda$execute$1(BuildCacheStep.java:75)
        at org.gradle.internal.Either$Right.fold(Either.java:176)
        at org.gradle.internal.execution.caching.CachingState.fold(CachingState.java:62)
        at org.gradle.internal.execution.steps.BuildCacheStep.execute(BuildCacheStep.java:73)
        at org.gradle.internal.execution.steps.BuildCacheStep.execute(BuildCacheStep.java:48)
        at org.gradle.internal.execution.steps.NeverUpToDateStep.execute(NeverUpToDateStep.java:34)
        at org.gradle.internal.execution.steps.NeverUpToDateStep.execute(NeverUpToDateStep.java:22)
        at org.gradle.internal.execution.steps.legacy.MarkSnapshottingInputsFinishedStep.execute(MarkSnapshottingInputsFinishedStep.java:37)
        at org.gradle.internal.execution.steps.legacy.MarkSnapshottingInputsFinishedStep.execute(MarkSnapshottingInputsFinishedStep.java:27)
        at org.gradle.internal.execution.steps.ResolveNonIncrementalCachingStateStep.executeDelegate(ResolveNonIncrementalCachingStateStep.java:50)
        at org.gradle.internal.execution.steps.AbstractResolveCachingStateStep.execute(AbstractResolveCachingStateStep.java:71)
        at org.gradle.internal.execution.steps.AbstractResolveCachingStateStep.execute(AbstractResolveCachingStateStep.java:39)
        at org.gradle.internal.execution.steps.ValidateStep.execute(ValidateStep.java:62)
        at org.gradle.internal.execution.steps.ValidateStep.execute(ValidateStep.java:40)
        at org.gradle.internal.execution.steps.AbstractCaptureStateBeforeExecutionStep.execute(AbstractCaptureStateBeforeExecutionStep.java:76)
        at org.gradle.internal.execution.steps.AbstractCaptureStateBeforeExecutionStep.execute(AbstractCaptureStateBeforeExecutionStep.java:45)
        at org.gradle.internal.execution.steps.legacy.MarkSnapshottingInputsStartedStep.execute(MarkSnapshottingInputsStartedStep.java:38)
        at org.gradle.internal.execution.steps.AssignImmutableWorkspaceStep.lambda$executeInTemporaryWorkspace$2(AssignImmutableWorkspaceStep.java:188)
        at org.gradle.internal.execution.workspace.impl.CacheBasedImmutableWorkspaceProvider$1.withTemporaryWorkspace(CacheBasedImmutableWorkspaceProvider.java:116)
        at org.gradle.internal.execution.steps.AssignImmutableWorkspaceStep.executeInTemporaryWorkspace(AssignImmutableWorkspaceStep.java:178)
        at org.gradle.internal.execution.steps.AssignImmutableWorkspaceStep.lambda$execute$0(AssignImmutableWorkspaceStep.java:119)
        at org.gradle.internal.execution.steps.AssignImmutableWorkspaceStep.execute(AssignImmutableWorkspaceStep.java:119)
        at org.gradle.internal.execution.steps.AssignImmutableWorkspaceStep.execute(AssignImmutableWorkspaceStep.java:88)
        at org.gradle.internal.execution.steps.ChoosePipelineStep.execute(ChoosePipelineStep.java:38)
        at org.gradle.internal.execution.steps.ChoosePipelineStep.execute(ChoosePipelineStep.java:23)
        at org.gradle.internal.execution.steps.ExecuteWorkBuildOperationFiringStep.lambda$execute$2(ExecuteWorkBuildOperationFiringStep.java:67)
        at org.gradle.internal.execution.steps.ExecuteWorkBuildOperationFiringStep.execute(ExecuteWorkBuildOperationFiringStep.java:67)
        at org.gradle.internal.execution.steps.ExecuteWorkBuildOperationFiringStep.execute(ExecuteWorkBuildOperationFiringStep.java:39)
        at org.gradle.internal.execution.steps.IdentityCacheStep.execute(IdentityCacheStep.java:46)
        at org.gradle.internal.execution.steps.IdentityCacheStep.execute(IdentityCacheStep.java:34)
        at org.gradle.internal.execution.steps.IdentifyStep.execute(IdentifyStep.java:47)
        at org.gradle.internal.execution.steps.IdentifyStep.execute(IdentifyStep.java:34)
        at org.gradle.internal.execution.impl.DefaultExecutionEngine$1.execute(DefaultExecutionEngine.java:64)
        at org.gradle.api.internal.catalog.DefaultDependenciesAccessors.executeWork(DefaultDependenciesAccessors.java:190)
        at org.gradle.api.internal.catalog.DefaultDependenciesAccessors.writeProjectAccessors(DefaultDependenciesAccessors.java:175)
        at org.gradle.api.internal.catalog.DefaultDependenciesAccessors.generateAccessors(DefaultDependenciesAccessors.java:159)
        ... 153 more


BUILD FAILED in 549ms

ShadowRZ avatar Sep 01 '25 03:09 ShadowRZ

Thanks @ShadowRZ. You shouldn't need to attach this plugin as a composite build, etc. The source code should be published with the artifact so you can step through it and your IDE will resolve. You can just run the task in debug mode and see what is adding to the configuration set dynamically. The PiTest example shows it adding a new configuration when the testImplementation configuration is resolved, but since Gradle does that lazily when needed their addition happens at execution time when materializing it via the DefaultDomainObjectCollection iterator. Since its lazy rather than eager at configuration time, this is a breaking usage of the Gradle APIs that has been incorrect for a number of major releases but the latest release is more aggressive after the grace period. Whatever plugins you're using which are corrupting the Gradle state needs to be found and fixed because they break the API contract. Most plugins don't need to iterate over the configurations, but those like this one or dependency-check which looks for CVEs will break.

ben-manes avatar Sep 01 '25 03:09 ben-manes

@ben-manes Ah, good to know. Also because I can't reproduce this problem when running the task with IDE, I instead used the CLI with -Dorg.gradle.debug=true --no-daemon --no-parallel --no-configuration-cache and create a remove JVM debug run configuration in Android Studio.

Narrowing down to the module that hit the error (my project is using multi module setup), I moved the apply of this plugin to the module's build.gradle.kts. When the ConcurrentModificationException was hit, it was processing debugAndroidTestCompileClasspath configuration, and I got the following stacktrace before the exception trace:

isProperUsage:1273, DefaultConfiguration (org.gradle.api.internal.artifacts.configurations)
warnOrFailOnInvalidUsage:1301, DefaultConfiguration (org.gradle.api.internal.artifacts.configurations)
warnOrFailOnInvalidUsage:1297, DefaultConfiguration (org.gradle.api.internal.artifacts.configurations)
getResolvedConfiguration:553, DefaultConfiguration (org.gradle.api.internal.artifacts.configurations)
getResolvedConfiguration:-1, DefaultLegacyConfiguration_Decorated (org.gradle.api.internal.artifacts.configurations)
getCurrentCoordinates:279, Resolver (com.github.benmanes.gradle.versions.updates)
resolve:56, Resolver (com.github.benmanes.gradle.versions.updates)
resolve:95, DependencyUpdates (com.github.benmanes.gradle.versions.updates)
lambda 'forEach' in 'resolveProjects':80, DependencyUpdates (com.github.benmanes.gradle.versions.updates)
forEach:215, DependencyUpdates (com.github.benmanes.gradle.versions.updates)
resolveProjects:76, DependencyUpdates (com.github.benmanes.gradle.versions.updates)
run:46, DependencyUpdates (com.github.benmanes.gradle.versions.updates)
dependencyUpdates:140, DependencyUpdatesTask (com.github.benmanes.gradle.versions.updates)
invokeSpecial:-1, DirectMethodHandle$Holder (java.lang.invoke)
invoke:-1, LambdaForm$MH/0x0000000100318800 (java.lang.invoke)
invokeExact_MT:-1, Invokers$Holder (java.lang.invoke)
invokeImpl:-1, DirectMethodHandleAccessor (jdk.internal.reflect)
invoke:-1, DirectMethodHandleAccessor (jdk.internal.reflect)
invoke:-1, Method (java.lang.reflect)
invoke:125, JavaMethod (org.gradle.internal.reflect)
doExecute:58, StandardTaskAction (org.gradle.api.internal.project.taskfactory)
execute:51, StandardTaskAction (org.gradle.api.internal.project.taskfactory)
execute:29, StandardTaskAction (org.gradle.api.internal.project.taskfactory)
run:252, TaskExecution$3 (org.gradle.api.internal.tasks.execution)
execute:29, DefaultBuildOperationRunner$1 (org.gradle.internal.operations)
execute:26, DefaultBuildOperationRunner$1 (org.gradle.internal.operations)
execute:66, DefaultBuildOperationRunner$2 (org.gradle.internal.operations)
execute:59, DefaultBuildOperationRunner$2 (org.gradle.internal.operations)
execute:166, DefaultBuildOperationRunner (org.gradle.internal.operations)
execute:59, DefaultBuildOperationRunner (org.gradle.internal.operations)
run:47, DefaultBuildOperationRunner (org.gradle.internal.operations)
executeAction:237, TaskExecution (org.gradle.api.internal.tasks.execution)
executeActions:220, TaskExecution (org.gradle.api.internal.tasks.execution)
executeWithPreviousOutputFiles:203, TaskExecution (org.gradle.api.internal.tasks.execution)
execute:170, TaskExecution (org.gradle.api.internal.tasks.execution)
executeInternal:105, ExecuteStep (org.gradle.internal.execution.steps)
access$000:44, ExecuteStep (org.gradle.internal.execution.steps)
call:59, ExecuteStep$1 (org.gradle.internal.execution.steps)
call:56, ExecuteStep$1 (org.gradle.internal.execution.steps)
execute:209, DefaultBuildOperationRunner$CallableBuildOperationWorker (org.gradle.internal.operations)
execute:204, DefaultBuildOperationRunner$CallableBuildOperationWorker (org.gradle.internal.operations)
execute:66, DefaultBuildOperationRunner$2 (org.gradle.internal.operations)
execute:59, DefaultBuildOperationRunner$2 (org.gradle.internal.operations)
execute:166, DefaultBuildOperationRunner (org.gradle.internal.operations)
execute:59, DefaultBuildOperationRunner (org.gradle.internal.operations)
call:53, DefaultBuildOperationRunner (org.gradle.internal.operations)
execute:56, ExecuteStep (org.gradle.internal.execution.steps)
execute:44, ExecuteStep (org.gradle.internal.execution.steps)
execute:42, CancelExecutionStep (org.gradle.internal.execution.steps)
executeWithoutTimeout:75, TimeoutStep (org.gradle.internal.execution.steps)
execute:55, TimeoutStep (org.gradle.internal.execution.steps)
execute:50, PreCreateOutputParentsStep (org.gradle.internal.execution.steps)
execute:28, PreCreateOutputParentsStep (org.gradle.internal.execution.steps)
execute:68, RemovePreviousOutputsStep (org.gradle.internal.execution.steps)
execute:38, RemovePreviousOutputsStep (org.gradle.internal.execution.steps)
execute:61, BroadcastChangingOutputsStep (org.gradle.internal.execution.steps)
execute:26, BroadcastChangingOutputsStep (org.gradle.internal.execution.steps)
execute:69, CaptureOutputsAfterExecutionStep (org.gradle.internal.execution.steps)
execute:46, CaptureOutputsAfterExecutionStep (org.gradle.internal.execution.steps)
execute:39, ResolveInputChangesStep (org.gradle.internal.execution.steps)
execute:28, ResolveInputChangesStep (org.gradle.internal.execution.steps)
executeWithoutCache:189, BuildCacheStep (org.gradle.internal.execution.steps)
lambda$execute$1:75, BuildCacheStep (org.gradle.internal.execution.steps)
apply:-1, BuildCacheStep$$Lambda/0x0000000100cd84b8 (org.gradle.internal.execution.steps)
fold:176, Either$Right (org.gradle.internal)
fold:62, CachingState (org.gradle.internal.execution.caching)
execute:73, BuildCacheStep (org.gradle.internal.execution.steps)
execute:48, BuildCacheStep (org.gradle.internal.execution.steps)
execute:46, StoreExecutionStateStep (org.gradle.internal.execution.steps)
execute:35, StoreExecutionStateStep (org.gradle.internal.execution.steps)
executeBecause:75, SkipUpToDateStep (org.gradle.internal.execution.steps)
lambda$execute$2:53, SkipUpToDateStep (org.gradle.internal.execution.steps)
get:-1, SkipUpToDateStep$$Lambda/0x0000000100cd26e8 (org.gradle.internal.execution.steps)
orElseGet:-1, Optional (java.util)
execute:53, SkipUpToDateStep (org.gradle.internal.execution.steps)
execute:35, SkipUpToDateStep (org.gradle.internal.execution.steps)
execute:37, MarkSnapshottingInputsFinishedStep (org.gradle.internal.execution.steps.legacy)
execute:27, MarkSnapshottingInputsFinishedStep (org.gradle.internal.execution.steps.legacy)
executeDelegate:49, ResolveIncrementalCachingStateStep (org.gradle.internal.execution.steps)
executeDelegate:27, ResolveIncrementalCachingStateStep (org.gradle.internal.execution.steps)
execute:71, AbstractResolveCachingStateStep (org.gradle.internal.execution.steps)
execute:39, AbstractResolveCachingStateStep (org.gradle.internal.execution.steps)
execute:64, ResolveChangesStep (org.gradle.internal.execution.steps)
execute:35, ResolveChangesStep (org.gradle.internal.execution.steps)
execute:62, ValidateStep (org.gradle.internal.execution.steps)
execute:40, ValidateStep (org.gradle.internal.execution.steps)
execute:76, AbstractCaptureStateBeforeExecutionStep (org.gradle.internal.execution.steps)
execute:45, AbstractCaptureStateBeforeExecutionStep (org.gradle.internal.execution.steps)
executeWithNonEmptySources:136, AbstractSkipEmptyWorkStep (org.gradle.internal.execution.steps)
execute:61, AbstractSkipEmptyWorkStep (org.gradle.internal.execution.steps)
execute:38, AbstractSkipEmptyWorkStep (org.gradle.internal.execution.steps)
execute:38, MarkSnapshottingInputsStartedStep (org.gradle.internal.execution.steps.legacy)
execute:36, LoadPreviousExecutionStateStep (org.gradle.internal.execution.steps)
execute:23, LoadPreviousExecutionStateStep (org.gradle.internal.execution.steps)
execute:75, HandleStaleOutputsStep (org.gradle.internal.execution.steps)
execute:41, HandleStaleOutputsStep (org.gradle.internal.execution.steps)
lambda$execute$0:35, AssignMutableWorkspaceStep (org.gradle.internal.execution.steps)
executeInWorkspace:-1, AssignMutableWorkspaceStep$$Lambda/0x0000000100cbe428 (org.gradle.internal.execution.steps)
withWorkspace:297, TaskExecution$4 (org.gradle.api.internal.tasks.execution)
execute:31, AssignMutableWorkspaceStep (org.gradle.internal.execution.steps)
execute:22, AssignMutableWorkspaceStep (org.gradle.internal.execution.steps)
execute:40, ChoosePipelineStep (org.gradle.internal.execution.steps)
execute:23, ChoosePipelineStep (org.gradle.internal.execution.steps)
lambda$execute$2:67, ExecuteWorkBuildOperationFiringStep (org.gradle.internal.execution.steps)
get:-1, ExecuteWorkBuildOperationFiringStep$$Lambda/0x00000001006b9058 (org.gradle.internal.execution.steps)
orElseGet:-1, Optional (java.util)
execute:67, ExecuteWorkBuildOperationFiringStep (org.gradle.internal.execution.steps)
execute:39, ExecuteWorkBuildOperationFiringStep (org.gradle.internal.execution.steps)
execute:46, IdentityCacheStep (org.gradle.internal.execution.steps)
execute:34, IdentityCacheStep (org.gradle.internal.execution.steps)
execute:47, IdentifyStep (org.gradle.internal.execution.steps)
execute:34, IdentifyStep (org.gradle.internal.execution.steps)
execute:64, DefaultExecutionEngine$1 (org.gradle.internal.execution.impl)
executeIfValid:132, ExecuteActionsTaskExecuter (org.gradle.api.internal.tasks.execution)
execute:121, ExecuteActionsTaskExecuter (org.gradle.api.internal.tasks.execution)
execute:41, ProblemsTaskPathTrackingTaskExecuter (org.gradle.api.internal.tasks.execution)
execute:46, FinalizePropertiesTaskExecuter (org.gradle.api.internal.tasks.execution)
execute:51, ResolveTaskExecutionModeExecuter (org.gradle.api.internal.tasks.execution)
execute:57, SkipTaskWithNoActionsExecuter (org.gradle.api.internal.tasks.execution)
execute:74, SkipOnlyIfTaskExecuter (org.gradle.api.internal.tasks.execution)
execute:36, CatchExceptionTaskExecuter (org.gradle.api.internal.tasks.execution)
executeTask:77, EventFiringTaskExecuter$1 (org.gradle.api.internal.tasks.execution)
call:55, EventFiringTaskExecuter$1 (org.gradle.api.internal.tasks.execution)
call:52, EventFiringTaskExecuter$1 (org.gradle.api.internal.tasks.execution)
execute:209, DefaultBuildOperationRunner$CallableBuildOperationWorker (org.gradle.internal.operations)
execute:204, DefaultBuildOperationRunner$CallableBuildOperationWorker (org.gradle.internal.operations)
execute:66, DefaultBuildOperationRunner$2 (org.gradle.internal.operations)
execute:59, DefaultBuildOperationRunner$2 (org.gradle.internal.operations)
execute:166, DefaultBuildOperationRunner (org.gradle.internal.operations)
execute:59, DefaultBuildOperationRunner (org.gradle.internal.operations)
call:53, DefaultBuildOperationRunner (org.gradle.internal.operations)
execute:52, EventFiringTaskExecuter (org.gradle.api.internal.tasks.execution)
execute:45, LocalTaskNodeExecutor (org.gradle.execution.plan)
execute:347, DefaultTaskExecutionGraph$InvokeNodeExecutorsAction (org.gradle.execution.taskgraph)
execute:334, DefaultTaskExecutionGraph$InvokeNodeExecutorsAction (org.gradle.execution.taskgraph)
lambda$execute$0:330, DefaultTaskExecutionGraph$BuildOperationAwareExecutionAction (org.gradle.execution.taskgraph)
run:-1, DefaultTaskExecutionGraph$BuildOperationAwareExecutionAction$$Lambda/0x0000000100c978e8 (org.gradle.execution.taskgraph)
with:84, CurrentBuildOperationRef (org.gradle.internal.operations)
execute:330, DefaultTaskExecutionGraph$BuildOperationAwareExecutionAction (org.gradle.execution.taskgraph)
execute:319, DefaultTaskExecutionGraph$BuildOperationAwareExecutionAction (org.gradle.execution.taskgraph)
execute:459, DefaultPlanExecutor$ExecutorWorker (org.gradle.execution.plan)
run:376, DefaultPlanExecutor$ExecutorWorker (org.gradle.execution.plan)
onExecute:64, ExecutorPolicy$CatchAndRecordFailures (org.gradle.internal.concurrent)
run:47, AbstractManagedExecutor$1 (org.gradle.internal.concurrent)
runWorker:-1, ThreadPoolExecutor (java.util.concurrent)
run:-1, ThreadPoolExecutor$Worker (java.util.concurrent)
runWith:-1, Thread (java.lang)
run:-1, Thread (java.lang)

That project's build.gradle.kts looks like this:

plugins {
    id("io.github.shadowrz.projectkafka.library")
    id("com.github.ben-manes.versions") version "0.52.0"
}

android {
    namespace = "io.github.shadowrz.projectkafka.libraries.deeplink"
}

where the io.github.shadowrz.projectkakfa.library convention plugin is defined to only include com.android.library and org.jetbrains.kotlin.android plugins and configure them.

Furthermore, AGP 8.12.1 is the first version of the plugin that would reproduce this problem, downgrading AGP (without affecting other plugins' versions) to 8.12.0 will allow dependencyUpdates task to succeed.

Additionally, it will only throw ConcurrentModificationException in a library module (applies com.android.library), not in a app (applies com.android.application).

Tested in a minimal Android Library module project too.

ShadowRZ avatar Sep 02 '25 03:09 ShadowRZ

It looks like fetching the android gradle plugin is a large undertaking. Its not available for simple browsing and requires downloading the universe to get something to look at. The browsable code seems to be many years out of date.

Presumably they are changing state but its going to be a while before it syncs locally for me to skim their code. I am not an android developer so it is foreign to me.

@jvandort has been extraordinarily helpful and generous with his advice, so he might have some pointers.

ben-manes avatar Sep 02 '25 05:09 ben-manes

No luck with AGP 8.13.0

@ben-manes Is it possible to use the published source artifacts of AGP on Google Maven repo as a reference source?

It should be at https://dl.google.com/dl/android/maven2/com/android/tools/build/gradle/8.12.1/gradle-8.12.1-sources.jar and https://dl.google.com/dl/android/maven2/com/android/tools/build/gradle-api/8.12.1/gradle-api-8.12.1-sources.jar

ShadowRZ avatar Sep 05 '25 01:09 ShadowRZ

Thanks. That is quite a lot of code! I tried skimming it but it was not easy to navigate. A few possibilities,

  1. SourceSetManager will create configurations for a sourceSet. Since Gradle now prefers to register sourceSets lazily, maybe when it has to materialize that then there are some weird interactions.
  2. There is a lot of complexity in variant building. I am not very familiar with that concept but it seems messy.

The easiest would be if Gradle switched to a concurrent collection to avoid the fail fast iterator. I suspect they'd frown on that as a plugin misuse that should be fixed, but this is a bit beyond me as well.

ben-manes avatar Sep 05 '25 03:09 ben-manes

It looks like fetching the android gradle plugin is a large undertaking. Its not available for simple browsing and requires downloading the universe to get something to look at. The browsable code seems to be many years out of date.

Presumably they are changing state but its going to be a while before it syncs locally for me to skim their code. I am not an android developer so it is foreign to me.

@jvandort has been extraordinarily helpful and generous with his advice, so he might have some pointers.

This is an old branch. The right branch is studio-main

ducrohet avatar Sep 05 '25 07:09 ducrohet

@ben-manes You might also want to refer to AGP 8.12.0 source code too, located in Google Maven repo at https://dl.google.com/dl/android/maven2/com/android/tools/build/gradle/8.12.0/gradle-8.12.0-sources.jar and https://dl.google.com/dl/android/maven2/com/android/tools/build/gradle-api/8.12.0/gradle-api-8.12.0-sources.jar

Diffing 8.12.0 and 8.12.1 code should give you an insight on what changed between these two versions.

ShadowRZ avatar Sep 07 '25 07:09 ShadowRZ