Skip to content

Scala: bump the default Metals version to 1.6.8 so sbt 2 builds can be imported - #1846

Open
merlinorg wants to merge 2 commits into
oraios:mainfrom
merlinorg:scala-default-metals-1.6.8
Open

Scala: bump the default Metals version to 1.6.8 so sbt 2 builds can be imported#1846
merlinorg wants to merge 2 commits into
oraios:mainfrom
merlinorg:scala-default-metals-1.6.8

Conversation

@merlinorg

Copy link
Copy Markdown
Contributor

Serena's default Metals, 1.6.4, cannot import any sbt 2 build. It bootstraps sbt-bloop 2.0.17, which is published for sbt 1 but not for sbt 2, so bloopInstall dies on an unresolvable plugin and no build server is ever started. Bumping the default to Metals 1.6.8 — which bootstraps sbt-bloop 2.1.1 — fixes it.

The failure mode is quiet rather than loud, which is worth knowing when reading bug reports about it. With no build target, Metals falls back to a standalone presentation compiler, which still answers within a single file; what stops working is everything that needs the build — cross-file references in particular. So the user's experience is "references across files silently return nothing", not an error.

There is also a second-order cost that outlives the session: the failed import leaves auto-generated metals.sbt files behind pinning the unresolvable plugin, so the user's own sbt is broken afterwards until they find and delete them.

Environment

  • Serena 1.7.0 (PyPI, uv tool install -p 3.13 'serena-agent>=1.7.0'), Python 3.13.5
  • Linux aarch64 (container), Temurin JDK 25.0.4, sbt launcher 2.0.5
  • Metals: the default, 1.6.4 — i.e. no metals_version in ls_specific_settings
  • Project under test: an sbt 2 build (sbt.version=2.0.6), Scala 3.3.8

Reproduction

A minimal fixture is enough — four files:

project/build.properties        sbt.version=2.0.6
build.sbt                       scalaVersion := "3.3.8"
                                name := "sbt2-metals-repro"
src/main/scala/Greeting.scala   object Greeting: def hello(name: String): String = s"hello $name"
                                object Caller:  val greeting = Greeting.hello("world")
.serena/project.yml             project_name: sbt2-metals-repro
                                language_servers: [scala]

Start Serena on it with no metals_version override and let Metals import the build. Serena answers the import prompt itself since #1769, so this needs no interaction.

Expected

Metals imports the build via bloopInstall, writes .bloop/*.json, and serves symbols across the project.

Actual

bloopInstall fails to resolve the plugin and no build target is ever produced:

INFO  Started: Metals version 1.6.4 in folders '/path/to/sbt2-fixture' for client Serena .
INFO  running '/usr/local/bin/sbt -Dbloop.export-jar-classifiers=sources bloopInstall'
INFO  [error] sbt.librarymanagement.ResolveException: Error downloading ch.epfl.scala:sbt-bloop_sbt2_3:2.0.17
INFO  [error]   not found: https://repo1.maven.org/maven2/ch/epfl/scala/sbt-bloop_sbt2_3/2.0.17/sbt-bloop_sbt2_3-2.0.17.pom
INFO  [error] failed to connect to server
INFO  time: ran 'sbt bloopInstall' in 5.63s

.bloop/ receives no *.json configs at all, and Metals thereafter logs no build target for: <file> for every file it is asked about. On a real multi-module project this also surfaces as Empty build targets. Expected at least one build target identifier.

One metals.sbt is left behind per project/ nesting level — two in this fixture, three in a project with a deeper meta-build — each containing:

// DO NOT EDIT! This file is auto-generated.
addSbtPlugin("ch.epfl.scala" % "sbt-bloop" % "2.0.17")

After which the user's own sbt fails on the same unresolvable plugin, until those files are deleted by hand:

$ sbt "print name"
[error] (update) sbt.librarymanagement.ResolveException: Error downloading ch.epfl.scala:sbt-bloop_sbt2_3:2.0.17

Analysis

(My reading, offered as such rather than as established fact.)

sbt plugin coordinates are cross-versioned by sbt version, and sbt-bloop 2.0.17 — which Metals 1.6.4 bootstraps — publishes only the sbt 1 artefact. That is why this is invisible to sbt 1 users and to CI. Checkable on Maven Central without running anything:

Artefact Result
sbt-bloop_sbt2_3 2.0.17 404
sbt-bloop_sbt2_3 2.0.18 200 — first sbt 2 release
sbt-bloop_sbt2_3 2.1.1 200
sbt-bloop_2.12_1.0 2.0.17 200 — the sbt 1 variant of the same version

Setting ls_specific_settings.scala.metals_version: "1.6.8" fixes it completely, which is what identifies the version as the whole cause. On a large sbt 2 monorepo, unchanged but for that one setting, Metals writes addSbtPlugin("ch.epfl.scala" % "sbt-bloop" % "2.1.1"), the import completes with 17 .bloop/*.json configs, and find_referencing_symbols returns 7 references across 4 files, 3 of them in files other than the definition's.

So a workaround exists and is documented — but it is per-project configuration for what is, for every sbt 2 user, a broken default.

Why 1.6.8 specifically

It is the current stable Metals release (v1.6.8, 2026-07-23); 2.0.0-M16 is a milestone and not a candidate. So this is a bump to latest stable rather than a leap, and it is the version I have been running against a large sbt 2 Scala monorepo for the past week.

Risk

Bounded, and CI should demonstrate it: .github/workflows/pytest.yml puts scala in MARKERS_JVM, and the Scala fixture at test/resources/repos/scala is an sbt 1 project (sbt.version=1.10.1). So the existing suite exercises exactly the population this change could regress, against a Metals four patch releases newer than the current default. Anyone who needs the old behaviour keeps metals_version as the escape hatch.

I have deliberately not touched test/resources/repos/scala or added an sbt 2 fixture. That would mean a second CI-visible Scala build and a slower JVM batch, and it seemed better to let you decide whether that is wanted than to bundle it into a version bump. Happy to add one if you would like it.

The diff also updates the metals_version default in the Scala table of docs/02-usage/050_configuration.md, which states it explicitly and would otherwise contradict the code.

Related

  • #838 is the precedent for this shape of change — it moved the default 1.6.2 → 1.6.4, and is what introduced the version this PR moves off.
  • #1769 is what makes this bug reachable: before Serena answered the import prompt, the import never ran, so the resolution failure had nowhere to happen.
  • #1816 is unrelated in mechanism but touches the same Bloop machinery; I ran into orphaned Bloop and sbt servers repeatedly while testing this, which is consistent with what is described there.

Disclosure

Prepared with the assistance of Claude Code (Claude Opus). I reproduced the failure myself on the environment above, verified every log excerpt, source citation and Maven Central result quoted here, and edited the text. I will answer follow-ups personally.

Checklist

  • This PR follows the guidelines in CONTRIBUTING.md regarding the scope of PRs.
  • For changes that add features or fix problems, I have added an entry to CHANGELOG.md, which concisely describes the change.

Metals 1.6.4 bootstraps sbt-bloop 2.0.17, which publishes an sbt 1 artefact
but no sbt 2 one, so on an sbt 2 build `bloopInstall` dies on an unresolvable
plugin and no build server is ever started. With no build target Metals falls
back to a standalone presentation compiler, so the failure is quiet: queries
within a single file still answer, and everything needing the build — cross-file
references in particular — silently returns nothing.

The failed import also leaves auto-generated `metals.sbt` files behind pinning
the unresolvable plugin, which breaks the user's own sbt until they are deleted.

Metals 1.6.8 bootstraps sbt-bloop 2.1.1, which is published for sbt 2. It is
the current stable Metals release; sbt-bloop has shipped an sbt 2 artefact
since 2.0.18.

The existing Scala test fixture is an sbt 1 project (sbt.version=1.10.1), so
the suite exercises the population this could regress.
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.

1 participant