Skip to content

[2.x] fix: Skip Conflict when dependency relocations form a cycle#8919

Merged
eed3si9n merged 3 commits intosbt:developfrom
bitloi:fix/8917-relocation-cycle-hang
Mar 19, 2026
Merged

[2.x] fix: Skip Conflict when dependency relocations form a cycle#8919
eed3si9n merged 3 commits intosbt:developfrom
bitloi:fix/8917-relocation-cycle-hang

Conversation

@bitloi
Copy link
Copy Markdown
Contributor

@bitloi bitloi commented Mar 18, 2026

Fixes #8924

Problem

sbt 1.12.6+ (and sbt 2.x with Coursier 2.1.25-M24) hangs indefinitely on update for projects using addSbtPlugin("com.typesafe.sbt" % "sbt-site" % "1.4.1"). The JVM stays in a tight loop; Ctrl+C often does not stop it (see #8917).

Root Cause

After resolution succeeds, SbtUpdateReport calls coursier.graph.Conflict(resolution), which builds DependencyTree nodes. Each node’s relocation helper follows Maven/Gradle relocation metadata with tail recursion but no cycle detection. For sbt-site’s graph, relocation chains revisit the same coordinates, so relocation never terminates (coursier#3578).

Solution

Add RelocationCycleDetector, which performs the same single relocation step as Coursier’s DependencyTree.Node.relocation and walks the implied graph. If any relocation chain would revisit a node, we skip coursier.graph.Conflict for affected configurations (resolution and artifacts are unchanged). One warning per update lists affected configuration names.

Alternatives considered: (1) bump Coursier to an unreleased fixed version — not available on Maven Central; (2) timeout around Conflict — nondeterministic and hides real errors; (3) vendor patched DependencyTree — would not affect Conflict in the coursier JAR (same-artifact linkage).

Testing

Verify:

./sbt "lmCoursier/testOnly lmcoursier.ResolutionSpec -- -z \"sbt-site\""
./sbt lmCoursier/test

Before / After

  • Before: update on sbt-site never finishes (infinite relocation expansion inside Conflict).
  • After: Update completes; classpath is correct; users may see one warning and slightly less eviction detail for configs with cyclic relocations.

Edge Cases Handled

  • Gradle + Maven relocation: same branches as Coursier’s relocation.
  • Only when resolution is done and clean: same guard as Coursier before applying relocations in DependencyTree.
  • Per-configuration: only configs whose graph contains a relocation cycle skip conflict extraction.
  • missingOk: existing try/catch unchanged.

bitloi added 2 commits March 18, 2026 08:40
…ite)

**Problem**
Coursier graph.Conflict -> DependencyTree relocation can loop forever when
Maven/Gradle relocation metadata forms a cycle (sbt-site 1.4.1, sbt#8917).

**Solution**
Detect relocation cycles with the same step logic as Coursier, skip Conflict
for affected configs, log once per update.

Generated-by: Claude
@bitloi
Copy link
Copy Markdown
Contributor Author

bitloi commented Mar 18, 2026

@eed3si9n Ready for review!

@eed3si9n
Copy link
Copy Markdown
Member

Thanks for identifying the root cause. Could you share your findings on coursier/coursier#3578 to help Coursier folks fix the issue as well?

@bitloi
Copy link
Copy Markdown
Contributor Author

bitloi commented Mar 18, 2026

Thanks for identifying the root cause. Could you share your findings on coursier/coursier#3578 to help Coursier folks fix the issue as well?

Posted a summary on coursier/coursier#3578 for upstream fix (cycle detection in DependencyTree.Node.relocation).

@bitloi bitloi requested a review from eed3si9n March 19, 2026 20:24
@eed3si9n
Copy link
Copy Markdown
Member

FYI - I already closed #8917 by rolling back the Coursier version, so I've created a fresh issue #8924 for this PR.

@bitloi
Copy link
Copy Markdown
Contributor Author

bitloi commented Mar 19, 2026

Thank you.

Copy link
Copy Markdown
Member

@eed3si9n eed3si9n left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks @bitloi!

@eed3si9n eed3si9n changed the title [2.x] fix: Skip Conflict when dependency relocations form a cycle (#8917) [2.x] fix: Skip Conflict when dependency relocations form a cycle Mar 19, 2026
@eed3si9n eed3si9n merged commit b24ecdd into sbt:develop Mar 19, 2026
15 checks passed
eed3si9n pushed a commit to eed3si9n/sbt that referenced this pull request Mar 23, 2026
…t#8919)

**Problem**
Coursier graph.Conflict -> DependencyTree relocation can loop forever when
Maven/Gradle relocation metadata forms a cycle (sbt-site 1.4.1).

**Solution**
Detect relocation cycles with the same step logic as Coursier, skip Conflict
for affected configs, log once per update.

Generated-by: Claude
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

stuck trying to resolve sbt-site 1.4.1

3 participants