fix: prevent ConfigurationCacheHackList fingerprint races on P2 (#3004) - #3006
Merged
nedtwigg merged 5 commits intoAug 15, 2026
Merged
Conversation
Gradle fingerprints stepsInternalEquality by serializing ConfigurationCacheHackList, which eagerly provisions Eclipse/P2 jars. Parallel multi-project builds raced on Solstice's disk cache and failed with "cannot be serialized" / "Failed to provision P2 dependencies" (diffplug#3004). - Serialize P2 queries process-wide in P2Provisioner.createDefault() - Share one DedupingP2Provisioner across subprojects in SpotlessTaskService - ConfigurationCacheHackList.toString() no longer calls hashCode() (avoids re-provisioning while Gradle formats the error message) Fixes diffplug#3004
…acklist-p2-serialize # Conflicts: # CHANGES.md # plugin-gradle/CHANGES.md # plugin-maven/CHANGES.md
lib-extra's `enforceSolsticeVersion` step requires the hardcoded "dev.equo.ide:solstice:X" in P2Provisioner to match libs.versions.toml, which is already at 1.8.2. main is inconsistent here, but ratchetFrom 'origin/main' hides it until a PR touches this file. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The previous commit made ConfigurationCacheHackList.toString() side-effect
free, which was correct but load-bearing: Gradle renders the value into
"Cannot fingerprint input property 'stepsInternalEquality': value '...'
cannot be serialized" and discards the cause. The old default toString()
called the overridden hashCode(), which evaluated the steps and threw the
actionable GradleException ("P2 dependencies not predeclared. Add Eclipse
formatter configuration to the `spotlessPredeclare` block...") out of
Gradle's message formatting, replacing the generic message.
Removing that side effect left users with only "cannot be serialized" and
broke 4 tests. Gradle builds that message only after serialization has
already thrown, so record the failure in writeObject and report it from
toString() instead. The message survives without toString() ever
evaluating step state.
Fixes SpotlessPredeclareIntegrationTest (P2/Maven/Groovy predeclareFails*)
and MultiProjectTest.predeclaredFails.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Sanity Check has been failing on nearly every PR with: Cannot fingerprint input property 'stepsInternalEquality': ... cannot be serialized > java.io.IOException: Failed to provision P2 dependencies Parallel fingerprinting of our own eclipse()/greclipse() steps races Solstice's on-disk P2 cache. We format ourselves with the published plugin pinned in settings.gradle, so the fix in this branch cannot help our CI until it is released and that pin is bumped. Turn parallel fingerprinting off until then. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Fixes #3004.
In multi-project builds, Gradle fingerprints many Spotless tasks in parallel. Each fingerprint serializes the
@InputstepsInternalEquality(ConfigurationCacheHackList.forEquality()), which eagerly resolves equality state for Eclipse/P2-backed steps (eclipse(),greclipse(), …). Concurrent Solstice P2 queries race on the on-disk cache and fail with:This matches the intermittent failure seen in junit-framework (
:junit-jupiter-api:spotlessJavawitheclipse()under Gradle 9.7 / Spotless 8.9.0) and earlier reports such as #2331.Changes
P2Provisioner.createDefault()— serialize all P2 queries onP2Provisioner.classso Solstice’s disk cache is not accessed concurrently.SpotlessTaskService— share oneDedupingP2Provisioneracross subprojects (not per-project) so parallel fingerprinting reuses a single in-memory cache + lock.ConfigurationCacheHackList.toString()— do not callhashCode(). DefaultObject.toString()fingerprints every step (may provision P2 again) while Gradle formats the “cannot be serialized” message, masking the real cause (see Spotless Gradle plugin 7.0.0: Eclipse / p2 download race condition #2331 stack traces).Test plan
./gradlew :testlib:test --tests com.diffplug.spotless.ConfigurationCacheHackListTest(2/2)./gradlew :plugin-gradle:test --tests com.diffplug.gradle.spotless.GradleProvisionerTest(19/19)./gradlew :plugin-gradle:test --tests com.diffplug.gradle.spotless.ConfigurationCacheTest(3/3)./gradlew spotlessApplyon touched sources