Skip to content

sbt-scalafmt 2.6.0 "corrupted class path" when consumed transitively through another sbt plugin #440

@Rossbro2

Description

@Rossbro2

Problem

sbt-scalafmt 2.6.0 fails with corrupted class path when it is consumed transitively through another sbt plugin, rather than declared directly in a project's plugins.sbt.

This works fine:

// project/plugins.sbt
addSbtPlugin("org.scalameta" %% "sbt-scalafmt" % "2.6.0")

This fails:

// my-sbt-plugin publishes with sbt-scalafmt 2.6.0 as a dependency
// downstream project's plugins.sbt
addSbtPlugin("com.example" %% "my-sbt-plugin" % "1.0.0")
// sbt-scalafmt 2.6.0 is resolved transitively

Error

[error] (Compile / scalafmtCheck) org.scalafmt.sbt.ScalafmtSbtReporter$ScalafmtSbtError:
  scalafmt: [v3.11.0] corrupted class path:
  [/path/to/.cache/coursier/v1/https/.../scalafmt-core_2.13-3.11.0.jar ...]

Root Cause

The 2.6.0 release (changelog) changed from scalafmt-dynamic's own isolated jar downloader to sbt's native dependency resolution ("Implement scalafmt-dynamic downloader using sbt").

When sbt-scalafmt is bundled inside another sbt plugin and consumed transitively:

  1. scalafmt-core 3.11.0 classes end up on the parent sbt classloader (via the host plugin's transitive dependencies)
  2. scalafmt-dynamic also loads scalafmt-core into its own isolated classloader
  3. The classloader validation in scalafmt-dynamic sees the same classes on both classloaders and fails with "corrupted class path"

When declared directly in plugins.sbt, the classes only appear on one classloader, so validation passes. This is why the issue only manifests in the transitive case.

Steps to Reproduce

  1. Create an sbt plugin that depends on sbt-scalafmt 2.6.0:
    // my-plugin/build.sbt
    sbtPlugin := true
    addSbtPlugin("org.scalameta" %% "sbt-scalafmt" % "2.6.0")
  2. Publish that plugin locally
  3. In a downstream project, consume the plugin transitively:
    // downstream/project/plugins.sbt
    addSbtPlugin("com.example" %% "my-plugin" % "1.0.0")
  4. Add a .scalafmt.conf with version = "3.11.0"
  5. Run sbt scalafmtCheck → fails with "corrupted class path"

Environment

  • sbt 1.12.10
  • Scala 2.13
  • Java: Amazon Corretto 25
  • useCoursier := false (Ivy resolution), though likely also affects Coursier
  • sbt-scalafmt 2.6.0 with scalafmt 3.11.0

Workaround

Revert to sbt-scalafmt 2.5.6, which uses the old isolated downloader approach and does not conflict with transitive classloading.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions