You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
NoClassDefFoundErrors when Gradle Configuration Cache is enabled #2850
When the Gradle Configuration Cache is enabled, I see intermittent java.lang.NoClassDefFoundError for googleJavaFormat classes for tasks like removeUnusedImports(), or org.eclipse.jdt classes when using the eclipse() formatter.
Spotless Gradle Plugin: 8.2.1
Gradle Wrapper: 9.3.0
Java: observed on 21 and 25
In my observations, I have only seen issues when the project has multiple modules, and only when running a command including clean. ./gradlew clean and ./gradlew build work in isolation, but when running ./gradlew clean build for instance, it results in an error similar to below when running it multiple times in a row.
Execution failed for task ':server:spotlessJavaCheck'.
> There were 1 lint error(s), they must be fixed or suppressed.
src/main/java/com/test/Main.java:LINE_UNDEFINED removeUnusedImports(java.lang.NoClassDefFoundError) com/google/googlejavaformat/java/RemoveUnusedImports (...)
Resolve these lints or suppress with `suppressLintsFor`
Reacted by BT, Manfred Hanke, Endre Stølsvik, Kuzmin Anton, Nick McDowall, Oliver Kopp, Dejan Stojadinović, Brett Kail, Kevin Fox, Mikhail Polivakha and 8 more
Just to confirm the issue on my end; I have a dual boot (Ubuntu and Windows) and so far I received this specific error just once on Windows OS.
Will try to run scripts I mentioned above for hours and report back with results.
> Task :module2:compileJava
Caching disabled for task ':module2:compileJava' because:
Build cache is disabled
Task ':module2:compileJava' is not up-to-date because:
Output property 'destinationDirectory' file C:\Work\spotless-cache-repro-master\module2\build\classes\java\main has been removed.
Output property 'destinationDirectory' file C:\Work\spotless-cache-repro-master\module2\build\classes\java\main\Main2.class has been removed.
Output property 'options.generatedSourceOutputDirectory' file C:\Work\spotless-cache-repro-master\module2\build\generated\sources\annotationProcessor\java\main has been removed.
and more...
The input changes require a full rebuild for incremental task ':module2:compileJava'.
Compilation mode: in-process compilation
Full recompilation is required because no incremental change information is available. This is usually caused by clean builds or changing compiler arguments.
Compiling with toolchain 'C:\Program Files\Eclipse Adoptium\jdk-25.0.2.10-hotspot'.
Compiling with JDK Java compiler API.
Class dependency analysis for incremental compilation took 0.004 secs.
Created classpath snapshot for incremental compilation in 0.0 secs.
FAILURE: Build failed with an exception.
* What went wrong:
Execution failed for task ':server:spotlessJavaCheck'.
> There were 1 lint error(s), they must be fixed or suppressed.
src/main/java/com/test/Main.java:LINE_UNDEFINED removeUnusedImports(java.lang.NoClassDefFoundError) com/google/common/collect/MapDifference (...)
Resolve these lints or suppress with `suppressLintsFor`
* Try:
> Run with --stacktrace option to get the stack trace.
> Run with --debug option to get more log output.
> Run with --scan to get full insights from a Build Scan (powered by Develocity).
> Get more help at https://help.gradle.org/.
BUILD FAILED in 1s
12 actionable tasks: 12 executed
Watched directory hierarchies: [C:\Work\spotless-cache-repro-master]
Configuration cache entry reused.
First round of testing (using the repo mentioned above) has been completed:
BUILD SUCCESSFUL in 10s
16 actionable tasks: 16 executed
Configuration cache entry reused.
**************************************************************************
### Build succeeded (execution number: 11017) -->> running again... ###
**************************************************************************
To honour the JVM settings for this build a single-use Daemon process will be forked. For more on this, please refer to https://docs.gradle.org/9.4.1/userguide/gradle_daemon.html#sec:disabling_the_daemon in the Gradle documentation.
Daemon will be stopped at the end of the build
Reusing configuration cache.
BUILD SUCCESSFUL in 11s
16 actionable tasks: 16 executed
Configuration cache entry reused.
**************************************************************************
### Build succeeded (execution number: 11018) -->> running again... ###
**************************************************************************
To honour the JVM settings for this build a single-use Daemon process will be forked. For more on this, please refer to https://docs.gradle.org/9.4.1/userguide/gradle_daemon.html#sec:disabling_the_daemon in the Gradle documentation.
> Starting Daemon
^C>>> Build failed on execution number: 11019 at Sun 22 Mar 14:56:20 CET 2026 <<<
dejan@dejan:~/Downloads/spotless-cache-repro-master$ git remote -v
origin https://github.com/dejan2609/spotless-cache-repro-master.git (fetch)
origin https://github.com/dejan2609/spotless-cache-repro-master.git (push)
dejan@dejan:~/Downloads/spotless-cache-repro-master$ git log --oneline -3
fa36b33 (HEAD -> main, origin/main) spotless gradle plugin 8.4.0 + Gradle 9.4.1
e3e03fd spotless gradle plugin 8.3.0 + Gradle 9.4.0
9ea7aa6 spotless gradle plugin 8.3.0 + Gradle 9.3.1
dejan@dejan:~/Downloads/spotless-cache-repro-master$ cat repeatUntilBuildFails.sh
#!/bin/bash
counter=0
while ./gradlew clean build --no-daemon --rerun-tasks; do
((counter++))
echo "**************************************************************************"
echo "### Build succeeded (execution number: $counter) -->> running again... ###"
echo "**************************************************************************"
done
((counter++))
echo ">>> Build failed on execution number: $counter at $(date) <<<"
dejan@dejan:~/Downloads/spotless-cache-repro-master$ date
Sun 22 Mar 14:56:56 CET 2026
dejan@dejan:~/Downloads/spotless-cache-repro-master$
I'll change the Gradle build command options and perform another round of tests.
@nedtwigg Second round of tests is completed and it 100 % confirms the issue description made by @shaunbrockhoff-wk:
BUILD SUCCESSFUL in 1s
16 actionable tasks: 16 executed
Configuration cache entry reused.
**************************************************************************
### Build succeeded (execution number: 64) -->> running again... ###
**************************************************************************
Reusing configuration cache.
BUILD SUCCESSFUL in 2s
16 actionable tasks: 16 executed
Configuration cache entry reused.
**************************************************************************
### Build succeeded (execution number: 65) -->> running again... ###
**************************************************************************
Reusing configuration cache.
> Task :server:spotlessJavaCheck FAILED
FAILURE: Build failed with an exception.
* What went wrong:
Execution failed for task ':server:spotlessJavaCheck'.
> There were 1 lint error(s), they must be fixed or suppressed.
src/main/java/com/test/Main.java:LINE_UNDEFINED removeUnusedImports(java.lang.NoClassDefFoundError) com/google/googlejavaformat/java/RemoveUnusedImports (...)
Resolve these lints or suppress with `suppressLintsFor`
* Try:
> Run with --stacktrace option to get the stack trace.
> Run with --info or --debug option to get more log output.
> Run with --scan to get full insights from a Build Scan (powered by Develocity).
> Get more help at https://help.gradle.org.
BUILD FAILED in 1s
11 actionable tasks: 11 executed
Configuration cache entry reused.
>>> Build failed on execution number: 66 at Fri 27 Mar 16:07:53 CET 2026 <<<
dejan@dejan:~/Downloads/spotless-cache-repro-master$ git remote -v
origin https://github.com/dejan2609/spotless-cache-repro-master.git (fetch)
origin https://github.com/dejan2609/spotless-cache-repro-master.git (push)
dejan@dejan:~/Downloads/spotless-cache-repro-master$ git log --oneline -3
2388ae9 (HEAD -> main, origin/main, NEW) Gradle build options `no-daemon` and `rerun-tasks` are removed out of 'repeatUntilBuildFails' scripts
fa36b33 spotless gradle plugin 8.4.0 + Gradle 9.4.1
e3e03fd spotless gradle plugin 8.3.0 + Gradle 9.4.0
dejan@dejan:~/Downloads/spotless-cache-repro-master$ cat repeatUntilBuildFails.sh
#!/bin/bash
counter=0
while ./gradlew clean build; do
((counter++))
echo "**************************************************************************"
echo "### Build succeeded (execution number: $counter) -->> running again... ###"
echo "**************************************************************************"
done
((counter++))
echo ">>> Build failed on execution number: $counter at $(date) <<<"
dejan@dejan:~/Downloads/spotless-cache-repro-master$ date
Fri 27 Mar 16:10:24 CET 2026
dejan@dejan:~/Downloads/spotless-cache-repro-master$
I am also experiencing this issue. It happens sporadically for me, I don't know when/why it happens. I was able to reliably fix it by removing my gradle caches(both .gradle/9.3.1 and !/.gradle/caches/9.3.1)
but recently it seems to go away on its own.
For me, I was able to reproduce this without running the clean task. in other words, I could repro it by running ./gradlew spotlessApply
Has there been any progress on investigating the root cause and coming up with a solution?
Is there any data I can provide to help with the investigation?
Some Hibernate developers have reported that they cleared their local caches in the past to workaround the problem. Please let us know if we can provide you any details that help you figure this out.
Confirming this on a large multi-module build (~120 Gradle subprojects), with a data point that I think narrows the root cause: the failure is formatter-agnostic.
Step 'google-java-format' found problem in 'X.java':
java.lang.IllegalStateException: zip file closed
at com.diffplug.spotless.FeatureClassLoader.findClass(FeatureClassLoader.java:79)
...
after which every subsequent class load from that classloader cascades into NoClassDefFoundError (com/google/common/collect/*, etc.). So the underlying event is the FeatureClassLoader's backing JAR being closed mid-build, not a missing class per se.
Formatter-swap A/B. I replaced googleJavaFormat("1.35.0") with eclipse("4.39") (Guava-free) and re-ran the identical cold build. The flake is unchanged — same IllegalStateException: zip file closed in FeatureClassLoader.findClass, except the cascading NoClassDefFoundErrors are now on org.eclipse.jdt.core.JavaCore and org.eclipse.jdt.core.formatter.CodeFormatter instead of Guava classes (3 of 3 cold runs). So the formatter — and Guava specifically — is incidental; the defect is in FeatureClassLoader itself.
Correlates with concurrent load.spotlessCheck run on its own is 100% reliable across many runs. The failure only appears when Spotless runs concurrently with a heavy compile graph — i.e. a cold clean build -x test --no-build-cache --rerun-tasks --continue across all modules — where it reproduces in roughly 2 of 3 runs (often more). Worth noting: unlike the minimal repro discussed above, --rerun-tasks does not hide it at this scale, which fits a concurrency/GC-pressure trigger on the shared FeatureClassLoader rather than (only) configuration-cache reuse.
FWIW, I just ran into the same issue (classloading issues left and right) right now while upgrading SAP/commerce-gradle-plugin to Spotless 8.6.0 and Gradle 9.5.1
The only reliable "fix" so far was to disable both the build and configuration cache.
EDIT - downgrading Spotless plugin to 8.4.0 also fixes it for my build
EDIT 2026-06-24 - nope, I just got lucky a few times. the only reliable fix is to disable the configuration cache completely.
Assorted Error Logs
gw clean build
Calculating task graph as no cached configuration is available for tasks: clean build
> Task :plugin-commons:spotlessKotlinGradleApply FAILED
> Task :plugin-commons:spotlessJavaApply FAILED
FAILURE: Build completed with 2 failures.
1: Task failed with an exception.
-----------
* What went wrong:
Execution failed for task ':plugin-commons:spotlessKotlinGradleApply' (registered by plugin 'mpern.commons').
> There were 1 lint error(s), they must be fixed or suppressed.
build.gradle.kts:LINE_UNDEFINED ktlint(java.lang.NoClassDefFoundError) com/pinterest/ktlint/rule/engine/api/EditorConfigDefaults (...)
Resolve these lints or suppress with `suppressLintsFor`
* Try:
> Run with --stacktrace option to get the stack trace.
> Run with --info or --debug option to get more log output.
> Run with --scan to get full insights from a Build Scan (powered by Develocity).
> Get more help at https://help.gradle.org.
==============================================================================
2: Task failed with an exception.
-----------
* What went wrong:
Execution failed for task ':plugin-commons:spotlessJavaApply' (registered by plugin 'mpern.commons').
> There were 2 lint error(s), they must be fixed or suppressed.
src/main/java/mpern/sap/commerce/commons/Constants.java:LINE_UNDEFINED removeUnusedImports(java.lang.NoClassDefFoundError) com/google/common/base/Predicate (...)
src/main/java/mpern/sap/commerce/commons/Constants.java:LINE_UNDEFINED eclipse jdt formatter(java.lang.reflect.InvocationTargetException) java.lang.reflect.InvocationTargetException (...)
Resolve these lints or suppress with `suppressLintsFor`
* Try:
> Run with --stacktrace option to get the stack trace.
> Run with --info or --debug option to get more log output.
> Run with --scan to get full insights from a Build Scan (powered by Develocity).
> Get more help at https://help.gradle.org.
==============================================================================
BUILD FAILED in 3s
23 actionable tasks: 6 executed, 4 from cache, 13 up-to-date
Configuration cache entry stored.
> Task :build-plugin:spotlessGroovy
The following nested jars are missing from /Users/I327130/.m2/repository/dev/equo/p2-data/nested-jars
jar:file:/Users/I327130/.gradle/caches/p2-data/bundle-pool/https-groovy.jfrog.io-artifactory-plugin--ldtmrg6m1JSts76B3o3M0Q---groovy-eclipse-integration-5.7.0-e4.35-/org.codehaus.groovy_5.0.0.v202503311943-e2503.jar!/eclipse-trace.jar
jar:file:/Users/I327130/.gradle/caches/p2-data/bundle-pool/https-groovy.jfrog.io-artifactory-plugin--ldtmrg6m1JSts76B3o3M0Q---groovy-eclipse-integration-5.7.0-e4.35-/org.codehaus.groovy_5.0.0.v202503311943-e2503.jar!/groovy-eclipse.jar
jar:file:/Users/I327130/.gradle/caches/p2-data/bundle-pool/https-groovy.jfrog.io-artifactory-plugin--ldtmrg6m1JSts76B3o3M0Q---groovy-eclipse-integration-5.7.0-e4.35-/org.codehaus.groovy_5.0.0.v202503311943-e2503.jar!/groovy-parser2.jar
jar:file:/Users/I327130/.gradle/caches/p2-data/bundle-pool/https-groovy.jfrog.io-artifactory-plugin--ldtmrg6m1JSts76B3o3M0Q---groovy-eclipse-integration-5.7.0-e4.35-/org.codehaus.groovy_5.0.0.v202503311943-e2503.jar!/lib/groovy-5.0.0.jar
jar:file:/Users/I327130/.gradle/caches/p2-data/bundle-pool/https-groovy.jfrog.io-artifactory-plugin--ldtmrg6m1JSts76B3o3M0Q---groovy-eclipse-integration-5.7.0-e4.35-/org.codehaus.groovy_5.0.0.v202503311943-e2503.jar!/lib/groovy-test-5.0.0.jar
jar:file:/Users/I327130/.gradle/caches/p2-data/bundle-pool/https-groovy.jfrog.io-artifactory-plugin--ldtmrg6m1JSts76B3o3M0Q---groovy-eclipse-integration-5.7.0-e4.35-/org.codehaus.groovy_5.0.0.v202503311943-e2503.jar!/lib/ivy-2.5.3.jar
jar:file:/Users/I327130/.gradle/caches/p2-data/bundle-pool/https-groovy.jfrog.io-artifactory-plugin--ldtmrg6m1JSts76B3o3M0Q---groovy-eclipse-integration-5.7.0-e4.35-/org.eclipse.jdt.groovy.core_5.7.0.v202503311943-e2503.jar!/nlcl.jar
Missing required bundle org.eclipse.jdt.debug needed by [org.eclipse.jdt.launching, org.eclipse.jdt.launching.macosx]
Missing required capability osgi.extender:osgi.extender=osgi.serviceloader.processor needed by org.apache.commons.commons-logging
Missing required capability osgi.serviceloader:osgi.serviceloader=org.apache.commons.logging.LogFactory needed by org.apache.commons.commons-logging
Recommend setting osgi.configuration.area to a directory, getDataFile will return null
Starting Groovy-Eclipse compiler resolver. Specified compiler level: unspecified
20 org.codehaus.groovy_5.0.0.v202503311943-e2503 RESOLVED
FAILURE: Build failed with an exception.
* What went wrong:
Execution failed for task ':test-utils:spotlessJavaApply' (registered by plugin 'mpern.commons').
> There were 3 lint error(s), they must be fixed or suppressed.
src/main/java/mpern/sap/commerce/build/ExtensionsTestUtils.java:LINE_UNDEFINED removeUnusedImports(java.lang.NoClassDefFoundError) com/google/common/collect/AbstractMapBasedMultimap (...)
src/main/java/mpern/sap/commerce/build/ProjectFolderTestUtils.java:LINE_UNDEFINED removeUnusedImports(java.lang.NoClassDefFoundError) com/google/common/collect/AbstractMapBasedMultimap (...)
src/main/java/mpern/sap/commerce/build/TestUtils.java:LINE_UNDEFINED removeUnusedImports(java.lang.NoClassDefFoundError) com/google/common/collect/AbstractMapBasedMultimap (...)
Resolve these lints or suppress with `suppressLintsFor`
* Try:
> Run with --stacktrace option to get the stack trace.
> Run with --info or --debug option to get more log output.
> Run with --scan to get full insights from a Build Scan (powered by Develocity).
> Get more help at https://help.gradle.org.
BUILD FAILED in 3s
54 actionable tasks: 45 executed, 9 up-to-date
Configuration cache entry stored.
❯ gw --no-build-cache clean build
Calculating task graph as configuration cache cannot be reused because directory 'build-plugin' has changed.
> Task :test-utils:spotlessJavaApply FAILED
> Task :build-plugin:spotlessGroovy
The following nested jars are missing from /Users/I327130/.m2/repository/dev/equo/p2-data/nested-jars
jar:file:/Users/I327130/.gradle/caches/p2-data/bundle-pool/https-groovy.jfrog.io-artifactory-plugin--ldtmrg6m1JSts76B3o3M0Q---groovy-eclipse-integration-5.7.0-e4.35-/org.codehaus.groovy_5.0.0.v202503311943-e2503.jar!/eclipse-trace.jar
jar:file:/Users/I327130/.gradle/caches/p2-data/bundle-pool/https-groovy.jfrog.io-artifactory-plugin--ldtmrg6m1JSts76B3o3M0Q---groovy-eclipse-integration-5.7.0-e4.35-/org.codehaus.groovy_5.0.0.v202503311943-e2503.jar!/groovy-eclipse.jar
jar:file:/Users/I327130/.gradle/caches/p2-data/bundle-pool/https-groovy.jfrog.io-artifactory-plugin--ldtmrg6m1JSts76B3o3M0Q---groovy-eclipse-integration-5.7.0-e4.35-/org.codehaus.groovy_5.0.0.v202503311943-e2503.jar!/groovy-parser2.jar
jar:file:/Users/I327130/.gradle/caches/p2-data/bundle-pool/https-groovy.jfrog.io-artifactory-plugin--ldtmrg6m1JSts76B3o3M0Q---groovy-eclipse-integration-5.7.0-e4.35-/org.codehaus.groovy_5.0.0.v202503311943-e2503.jar!/lib/groovy-5.0.0.jar
jar:file:/Users/I327130/.gradle/caches/p2-data/bundle-pool/https-groovy.jfrog.io-artifactory-plugin--ldtmrg6m1JSts76B3o3M0Q---groovy-eclipse-integration-5.7.0-e4.35-/org.codehaus.groovy_5.0.0.v202503311943-e2503.jar!/lib/groovy-test-5.0.0.jar
jar:file:/Users/I327130/.gradle/caches/p2-data/bundle-pool/https-groovy.jfrog.io-artifactory-plugin--ldtmrg6m1JSts76B3o3M0Q---groovy-eclipse-integration-5.7.0-e4.35-/org.codehaus.groovy_5.0.0.v202503311943-e2503.jar!/lib/ivy-2.5.3.jar
jar:file:/Users/I327130/.gradle/caches/p2-data/bundle-pool/https-groovy.jfrog.io-artifactory-plugin--ldtmrg6m1JSts76B3o3M0Q---groovy-eclipse-integration-5.7.0-e4.35-/org.eclipse.jdt.groovy.core_5.7.0.v202503311943-e2503.jar!/nlcl.jar
Missing required bundle org.eclipse.jdt.debug needed by [org.eclipse.jdt.launching, org.eclipse.jdt.launching.macosx]
Missing required capability osgi.extender:osgi.extender=osgi.serviceloader.processor needed by org.apache.commons.commons-logging
Missing required capability osgi.serviceloader:osgi.serviceloader=org.apache.commons.logging.LogFactory needed by org.apache.commons.commons-logging
Recommend setting osgi.configuration.area to a directory, getDataFile will return null
Starting Groovy-Eclipse compiler resolver. Specified compiler level: unspecified
20 org.codehaus.groovy_5.0.0.v202503311943-e2503 RESOLVED
FAILURE: Build failed with an exception.
* What went wrong:
Execution failed for task ':test-utils:spotlessJavaApply' (registered by plugin 'mpern.commons').
> There were 3 lint error(s), they must be fixed or suppressed.
src/main/java/mpern/sap/commerce/build/ExtensionsTestUtils.java:LINE_UNDEFINED removeUnusedImports(java.lang.NoClassDefFoundError) com/google/common/collect/AbstractMapBasedMultimap (...)
src/main/java/mpern/sap/commerce/build/ProjectFolderTestUtils.java:LINE_UNDEFINED removeUnusedImports(java.lang.NoClassDefFoundError) com/google/common/collect/AbstractMapBasedMultimap (...)
src/main/java/mpern/sap/commerce/build/TestUtils.java:LINE_UNDEFINED removeUnusedImports(java.lang.NoClassDefFoundError) com/google/common/collect/AbstractMapBasedMultimap (...)
Resolve these lints or suppress with `suppressLintsFor`
* Try:
> Run with --stacktrace option to get the stack trace.
> Run with --info or --debug option to get more log output.
> Run with --scan to get full insights from a Build Scan (powered by Develocity).
> Get more help at https://help.gradle.org.
BUILD FAILED in 3s
54 actionable tasks: 45 executed, 9 up-to-date
Configuration cache entry stored.
❯ gw --no-configuration-cache clean build
> Task :plugin-commons:spotlessJavaApply FAILED
FAILURE: Build failed with an exception.
* What went wrong:
Execution failed for task ':plugin-commons:spotlessJavaApply' (registered by plugin 'mpern.commons').
> There were 2 lint error(s), they must be fixed or suppressed.
src/main/java/mpern/sap/commerce/commons/Constants.java:LINE_UNDEFINED removeUnusedImports(java.lang.NoClassDefFoundError) com/google/common/base/Predicate (...)
src/main/java/mpern/sap/commerce/commons/Constants.java:LINE_UNDEFINED eclipse jdt formatter(java.lang.reflect.InvocationTargetException) java.lang.reflect.InvocationTargetException (...)
Resolve these lints or suppress with `suppressLintsFor`
* Try:
> Run with --stacktrace option to get the stack trace.
> Run with --info or --debug option to get more log output.
> Run with --scan to get full insights from a Build Scan (powered by Develocity).
> Get more help at https://help.gradle.org.
BUILD SUCCESSFUL in 2s
16 actionable tasks: 16 executed
Configuration cache entry reused.
**************************************************************************
### Build succeeded (execution number: 93) -->> running again... ###
**************************************************************************
Reusing configuration cache.
> Task :server:spotlessJavaCheck FAILED
FAILURE: Build failed with an exception.
* What went wrong:
Execution failed for task ':server:spotlessJavaCheck' (registered in build file 'build.gradle').
> There were 1 lint error(s), they must be fixed or suppressed.
src/main/java/com/test/Main.java:LINE_UNDEFINED removeUnusedImports(java.lang.NoClassDefFoundError) com/google/googlejavaformat/java/RemoveUnusedImports$1 (...)
Resolve these lints or suppress with `suppressLintsFor`
* Try:
> Run with --stacktrace option to get the stack trace.
> Run with --info or --debug option to get more log output.
> Run with --scan to get full insights from a Build Scan (powered by Develocity).
> Get more help at https://help.gradle.org.
BUILD FAILED in 1s
11 actionable tasks: 11 executed
Configuration cache entry reused.
>>> Build failed on execution number: 94 at Sat 27 Jun 11:41:32 CEST 2026 <<<
dejan@dejan:~/Downloads/spotless-cache-repro-master$ date
Sat 27 Jun 11:48:52 CEST 2026
dejan@dejan:~/Downloads/spotless-cache-repro-master$ git remote -v
origin https://github.com/dejan2609/spotless-cache-repro-master.git (fetch)
origin https://github.com/dejan2609/spotless-cache-repro-master.git (push)
dejan@dejan:~/Downloads/spotless-cache-repro-master$ git log -3 --oneline
dc7842e (HEAD -> main) spotless gradle plugin 8.7.0 + Gradle 9.6.1
2388ae9 (origin/main) Gradle build options `no-daemon` and `rerun-tasks` are removed out of 'repeatUntilBuildFails' scripts
fa36b33 spotless gradle plugin 8.4.0 + Gradle 9.4.1
dejan@dejan:~/Downloads/spotless-cache-repro-master$ cat repeatUntilBuildFails.sh
#!/bin/bash
counter=0
while ./gradlew clean build; do
((counter++))
echo "**************************************************************************"
echo "### Build succeeded (execution number: $counter) -->> running again... ###"
echo "**************************************************************************"
done
((counter++))
echo ">>> Build failed on execution number: $counter at $(date) <<<"
dejan@dejan:~/Downloads/spotless-cache-repro-master$
Hi — I'm Claude (an AI assistant), investigating this on behalf of a user whose
build hits it. Posting with his permission. Everything below is measured on his
project unless I've flagged it as inference; happy to run further experiments if
any of it is useful.
Short version: I don't think the configuration cache is the trigger, and I
think the culprit is SpotlessCache.clearOnce being called from clean's doLast with no ordering against the spotless tasks.
A faster reproduction
The repro linked above fails roughly 1 build in 90. On an 8-module Java build
(Gradle 9.6.1, JDK 21, macOS) the rate is about 2 in 3, and the trigger isolates
cleanly. Same task list either way, --no-build-cache so spotless genuinely
executes:
invocation
failures
gradlew clean then gradlew classes testClasses spotlessJavaCheck
spotlessJavaCheck alone, with no clean anywhere and --rerun-tasks, was
0/8. Adding compilation to the graph is what makes it fail — my reading is that
it lets a module's spotless task start before some other project's clean has
finished, which pure clean+spotless does not.
The configuration cache changes the rate (roughly 6/8 on, 3/8 off) but not the
outcome, so I'd suggest the issue title is misleading — matching the earlier
comment here that reproduced it with --no-configuration-cache.
Mechanism
Reading the jars as shipped in 8.8.0: SpotlessCache holds a JVM-global map of
provisioned URLClassLoaders, and clearOnce doesn't just drop them — it
closes them. SpotlessPlugin.apply registers that as a doLast on clean,
once per build, on whichever clean finishes first. Nothing orders it against
any spotless* task.
So in a single clean build, the clear can land after a module has already
built and cached its formatter. Every class that formatter has already loaded
keeps working; the next one it needs lazily does not. That matches the symptom
exactly — the failures land on lazily-touched classes rather than on entry
points, and which class is named varies run to run:
Foo.java:LINE_UNDEFINED palantir-java-format(java.lang.NoClassDefFoundError) com/google/common/base/CharMatcher$None
Foo.java:LINE_UNDEFINED palantir-java-format(java.lang.NoClassDefFoundError) Could not initialize class com.palantir.javaformat.java.ImportOrderer
Foo.java:LINE_UNDEFINED removeUnusedImports(java.lang.NoClassDefFoundError) com/google/googlejavaformat/java/Formatter
Foo.java:LINE_UNDEFINED removeUnusedImports(java.lang.NoClassDefFoundError) com/google/common/collect/Iterators
(file names redacted)
Roughly as often it surfaces instead as:
Foo.java:LINE_UNDEFINED palantir-java-format(java.lang.NullPointerException) Cannot invoke "java.util.List.getClass()" because "list" is null
That message is what Collections.unmodifiableList(null) produces. FileSignature.files is transient, so a FileSignature that has been through
Java serialization has a null file list, and files() then throws exactly this
while jarUrls() would yield a loader with no jars at all. I have not proven
that path is what's hit — flagging it as inference, but it may be a second route
to the same class of failure and worth a look alongside the first.
Prior art
This looks like #243 resurfacing. That was fixed by #501 (merged 2020-01-01),
which introduced clearOnce so the clear happens once per build rather than
once per project — but it never ordered the clear after the spotless tasks, so
the race is still reachable whenever clean shares an invocation with anything
that formats.
Things I ruled out, so nobody repeats them
Each tested rather than reasoned about:
Guava version skew. Not it. Two Guava versions do end up in such a build
(palantir-java-format pulls one, google-java-format for removeUnusedImports
pulls another), which makes this a very convincing red herring — the user's
build had carried a Guava pin against this error for years. But every Guava
version involved contains all three classes reported missing.
Error Prone co-loading. 6/8 failures with it disabled entirely.
Daemon memory. 6/6 failures at -Xmx3g with a 1g metaspace, versus
Gradle's 512m/384m defaults.
Plugin version. 7.2.1, 8.8.0 and 8.9.0 all fail at similar rates, so
there's nothing to upgrade to.
Parallelism. Fails with --no-parallel too.
Workaround
For anyone blocked, ordering spotless after every clean fixes it without
touching the plugin. mustRunAfter, so it never causes a clean:
Every clean in every project, since the cache and the clear are both global to
the daemon — one project's clean can close a loader another project's spotlessJava is holding. That took the failing command from 6/8 to 0/12,
with three further green clean builds (~100 tasks genuinely executed, one
under --no-daemon), and spotlessApply reformatting nothing.
A fix in the plugin might be to make clearOnce a finalizedBy-style step
ordered after the spotless tasks, or to stop closing loaders that may still be
referenced and let them be collected — but you'll have much better judgement
than me on which fits the design.
Execute Gradle build in a loop:./repeatUntilBuildFails.sh clean build
BUILD SUCCESSFUL in 3s
16 actionable tasks: 16 executed
Configuration cache entry reused.
**************************************************************************
### Build succeeded (execution number: 69) -->> running again... ###
**************************************************************************
Reusing configuration cache.
> Task :server:spotlessJavaCheck FAILED
FAILURE: Build failed with an exception.
* What went wrong:
Execution failed for task ':server:spotlessJavaCheck' (registered in build file 'build.gradle').
> There were 1 lint error(s), they must be fixed or suppressed.
src/main/java/com/test/Main.java:LINE_UNDEFINED removeUnusedImports(java.lang.NoClassDefFoundError) com/google/googlejavaformat/java/RemoveUnusedImports (...)
Resolve these lints or suppress with `suppressLintsFor`
* Try:
> Run with --stacktrace option to get the stack trace.
> Run with --info or --debug option to get more log output.
> Run with --scan to get full insights from a Build Scan (powered by Develocity).
> Get more help at https://help.gradle.org.
BUILD FAILED in 3s
15 actionable tasks: 15 executed
Configuration cache entry reused.
>>> Build failed on execution number: 70 at Tue 8 Sep 13:09:37 CEST 2026 <<<
The configuration cache changes the rate (roughly 6/8 on, 3/8 off) but not the
outcome, so I'd suggest the issue title is misleading — matching the earlier
comment here that reproduced it with --no-configuration-cache.
I got different results on my side: build works flawlessly when switch --no-configuration-cache is used.
Activity
dejan2609 commentedon Mar 7, 2026
@shaunbrockhoff-wk I hope you don't mind the fact that I took your minimal reproduction zip and created a Git repo: https://github.com/dejan2609/spotless-cache-repro-master with some sprinkled changes:
dejan2609 commentedon Mar 10, 2026
ℹ️ Update: I expanded the POC git repo mentioned above to enable easy testing.
How to use it:
./gradlew clean build --no-daemon --rerun-tasksin a loop until build fails:./repeatUntilBuildFails.sh.\repeatUntilBuildFails.ps1--no-daemonand--rerun-tasksare hiding the issue, see this comment #2850 (comment) belowdejan2609 commentedon Mar 14, 2026
Just to confirm the issue on my end; I have a dual boot (Ubuntu and Windows) and so far I received this specific error just once on Windows OS.
Will try to run scripts I mentioned above for hours and report back with results.
dejan2609 commentedon Mar 16, 2026
FYI @nedtwigg
dejan2609 commentedon Mar 22, 2026
First round of testing (using the repo mentioned above) has been completed:
I'll change the Gradle build command options and perform another round of tests.
dejan2609 commentedon Mar 27, 2026
@nedtwigg Second round of tests is completed and it 100 % confirms the issue description made by @shaunbrockhoff-wk:
KAFKA-20182: Remove removeUnusedImports and upgrade spotless to 8.4.0
KAFKA-20182: Remove removeUnusedImports and upgrade spotless to 8.4.0
KAFKA-20182 Remove removeUnusedImports and upgrade spotless to 8.4.0 (#…
KAFKA-20182 Remove removeUnusedImports and upgrade spotless to 8.4.0 (a…
danbress commentedon Apr 22, 2026
Hi team,
I am also experiencing this issue. It happens sporadically for me, I don't know when/why it happens. I was able to reliably fix it by removing my gradle caches(both
.gradle/9.3.1and!/.gradle/caches/9.3.1)but recently it seems to go away on its own.
For me, I was able to reproduce this without running the
cleantask. in other words, I could repro it by running./gradlew spotlessApplyHas there been any progress on investigating the root cause and coming up with a solution?
Is there any data I can provide to help with the investigation?
beikov commentedon May 22, 2026
We also recently ran into this problem on our CI: https://ci.hibernate.org/blue/organizations/jenkins/hibernate-orm-nightly/detail/main/1171/pipeline/432/
Some Hibernate developers have reported that they cleared their local caches in the past to workaround the problem. Please let us know if we can provide you any details that help you figure this out.
Spotless plugin: 8.5.1
Gradle: 9.5.1
JDK: Temurin JDK 25.0.2+10
andreasaronssondg commentedon May 27, 2026
Confirming this on a large multi-module build (~120 Gradle subprojects), with a data point that I think narrows the root cause: the failure is formatter-agnostic.
Stack: Spotless 8.5.1, Gradle 9.x, Temurin JDK 25,
org.gradle.configuration-cache=true+org.gradle.parallel=true.The first failure in each run is consistently:
after which every subsequent class load from that classloader cascades into
NoClassDefFoundError(com/google/common/collect/*, etc.). So the underlying event is theFeatureClassLoader's backing JAR being closed mid-build, not a missing class per se.Formatter-swap A/B. I replaced
googleJavaFormat("1.35.0")witheclipse("4.39")(Guava-free) and re-ran the identical cold build. The flake is unchanged — sameIllegalStateException: zip file closedinFeatureClassLoader.findClass, except the cascadingNoClassDefFoundErrors are now onorg.eclipse.jdt.core.JavaCoreandorg.eclipse.jdt.core.formatter.CodeFormatterinstead of Guava classes (3 of 3 cold runs). So the formatter — and Guava specifically — is incidental; the defect is inFeatureClassLoaderitself.Correlates with concurrent load.
spotlessCheckrun on its own is 100% reliable across many runs. The failure only appears when Spotless runs concurrently with a heavy compile graph — i.e. a coldclean build -x test --no-build-cache --rerun-tasks --continueacross all modules — where it reproduces in roughly 2 of 3 runs (often more). Worth noting: unlike the minimal repro discussed above,--rerun-tasksdoes not hide it at this scale, which fits a concurrency/GC-pressure trigger on the sharedFeatureClassLoaderrather than (only) configuration-cache reuse.Happy to provide full logs or test a patch.
mpern commentedon Jun 9, 2026
FWIW, I just ran into the same issue (classloading issues left and right) right now while upgrading SAP/commerce-gradle-plugin to Spotless 8.6.0 and Gradle 9.5.1
The only reliable "fix" so far was to disable both the build and configuration cache.
EDIT - downgrading Spotless plugin to 8.4.0 also fixes it for my build
EDIT 2026-06-24 - nope, I just got lucky a few times. the only reliable fix is to disable the configuration cache completely.
Assorted Error Logs
chore(deps): upgrade Spring Boot to 4.1.0, isolate Spotless in CI (#564)
Gradle 9.6.x + Configuration Cache (#120)
dejan2609 commentedon Jun 27, 2026
ℹ️ Still fails with spotless gradle plugin 8.7.0 and Gradle 9.6.1.
Scenario:
./repeatUntilBuildFails.shKAFKA-20730 Remove scalafmt from streams-scala Spotless config (#22668)
Remove `removeUnusedImports()` due to diffplug/spotless#2850
Disable Gradle's configuration cache and parallel execution
codeaholics commentedon Aug 6, 2026
Hi — I'm Claude (an AI assistant), investigating this on behalf of a user whose
build hits it. Posting with his permission. Everything below is measured on his
project unless I've flagged it as inference; happy to run further experiments if
any of it is useful.
Short version: I don't think the configuration cache is the trigger, and I
think the culprit is
SpotlessCache.clearOncebeing called fromclean'sdoLastwith no ordering against the spotless tasks.A faster reproduction
The repro linked above fails roughly 1 build in 90. On an 8-module Java build
(Gradle 9.6.1, JDK 21, macOS) the rate is about 2 in 3, and the trigger isolates
cleanly. Same task list either way,
--no-build-cacheso spotless genuinelyexecutes:
gradlew cleanthengradlew classes testClasses spotlessJavaCheckgradlew clean classes testClasses spotlessJavaCheckspotlessJavaCheckalone, with nocleananywhere and--rerun-tasks, was0/8. Adding compilation to the graph is what makes it fail — my reading is that
it lets a module's spotless task start before some other project's
cleanhasfinished, which pure
clean+spotless does not.The configuration cache changes the rate (roughly 6/8 on, 3/8 off) but not the
outcome, so I'd suggest the issue title is misleading — matching the earlier
comment here that reproduced it with
--no-configuration-cache.Mechanism
Reading the jars as shipped in 8.8.0:
SpotlessCacheholds a JVM-global map ofprovisioned
URLClassLoaders, andclearOncedoesn't just drop them — itcloses them.
SpotlessPlugin.applyregisters that as adoLastonclean,once per build, on whichever
cleanfinishes first. Nothing orders it againstany
spotless*task.So in a single
clean build, the clear can land after a module has alreadybuilt and cached its formatter. Every class that formatter has already loaded
keeps working; the next one it needs lazily does not. That matches the symptom
exactly — the failures land on lazily-touched classes rather than on entry
points, and which class is named varies run to run:
(file names redacted)
Roughly as often it surfaces instead as:
That message is what
Collections.unmodifiableList(null)produces.FileSignature.filesistransient, so aFileSignaturethat has been throughJava serialization has a null file list, and
files()then throws exactly thiswhile
jarUrls()would yield a loader with no jars at all. I have not proventhat path is what's hit — flagging it as inference, but it may be a second route
to the same class of failure and worth a look alongside the first.
Prior art
This looks like #243 resurfacing. That was fixed by #501 (merged 2020-01-01),
which introduced
clearOnceso the clear happens once per build rather thanonce per project — but it never ordered the clear after the spotless tasks, so
the race is still reachable whenever
cleanshares an invocation with anythingthat formats.
Things I ruled out, so nobody repeats them
Each tested rather than reasoned about:
(palantir-java-format pulls one, google-java-format for
removeUnusedImportspulls another), which makes this a very convincing red herring — the user's
build had carried a Guava pin against this error for years. But every Guava
version involved contains all three classes reported missing.
-Xmx3gwith a 1g metaspace, versusGradle's 512m/384m defaults.
there's nothing to upgrade to.
--no-paralleltoo.Workaround
For anyone blocked, ordering spotless after every
cleanfixes it withouttouching the plugin.
mustRunAfter, so it never causes a clean:allprojects { def everyClean = rootProject.allprojects.collect { p -> p.tasks.matching { it.name == 'clean' } } tasks.matching { it.name.startsWith('spotless') }.configureEach { mustRunAfter everyClean } }Every clean in every project, since the cache and the clear are both global to
the daemon — one project's
cleancan close a loader another project'sspotlessJavais holding. That took the failing command from 6/8 to 0/12,with three further green
clean builds (~100 tasks genuinely executed, oneunder
--no-daemon), andspotlessApplyreformatting nothing.A fix in the plugin might be to make
clearOnceafinalizedBy-style stepordered after the spotless tasks, or to stop closing loaders that may still be
referenced and let them be collected — but you'll have much better judgement
than me on which fits the design.
Disable configuration cache repo-wide (diffplug/spotless#2850)
Update stale config-cache-is-on claims after disabling it
Update stale config-cache-is-on claims after disabling it
Fix final review round findings in module-release-scripts
dejan2609 commentedon Sep 8, 2026
I just upgraded gradle and plugin versions and the issue persists: https://github.com/dejan2609/spotless-cache-repro-master/tree/main
Environment:
Execute Gradle build in a loop:
./repeatUntilBuildFails.sh clean builddejan2609 commentedon Sep 8, 2026
I got different results on my side: build works flawlessly when switch
--no-configuration-cacheis used.Environment:
Execute Gradle build in a loop:
./repeatUntilBuildFails.sh clean build --no-configuration-cachedejan2609 commentedon Sep 8, 2026
@nedtwigg can you please mark this bug as valid ?