3 minutes read
Scala and sbt
The scala detector reports Scala and sbt releases that no longer receive maintenance, as declared in .scala-version, build.sbt, and project/build.properties. It is stable: its level is recorded as stable in benchmarks/thresholds.json, and the precision floor is enforced on the public corpus (see Decision 0013). Its lifecycle rules are in registry/scala.json and ship with the package (see Lifecycle data).
What it reads
| File | Declaration |
|---|---|
.scala-version |
A single pinned Scala version on a line by itself |
build.sbt |
A literal scalaVersion := "…", ThisBuild / scalaVersion := "…", or scalaVersion in ThisBuild := "…" |
project/build.properties |
An sbt.version=… pin |
It walks the repository up to eight directories deep (at most 500 matching files) and does not follow symbolic links. It skips .git, node_modules, vendor, dist, build, target, .venv, venv, .bloop, .metals, .scala-build, fixtures, __fixtures__, and testdata. A build.properties file is read only when its parent directory is named project. Scala and sbt are never run, and nothing is fetched.
What it reports
- A Scala 2.11 version pinned in
.scala-versionor as an exactscalaVersionvalue inbuild.sbt. The Scala development guarantees page states that Scala 2.11 reached end-of-life in 2016. Reported at high severity. - A Scala 3.0, 3.1, or 3.2 version pinned the same way. Non-LTS Scala 3 minors receive patches only until the next minor ships, so those lines are frozen. Reported at high severity.
- An sbt 0.13.x version pinned in
project/build.properties. The sbt download page lists 0.13.x as end of life on 2018-11-30. Reported at high severity.
Each finding carries its rule's source, replacement, migration steps, and verification commands.
How versions are matched
- An exact version (a
.scala-versionpin, an exactscalaVersionvalue, or ansbt.versionpin) uses the first rule whoseversrange contains it. A rule whoseversis malformed is skipped, so it does not hide a later rule. - A constraint that is not an exact
major.minor.patchpin is matched only against a rule that covers every version of that package. It is never reported as an old Scala runtime, because the project may build with a newer one. - Scala is matched as
pkg:generic/scala, and sbt aspkg:generic/sbt.
What it intentionally does not judge
- Partial Scala versions such as
2.11or3.3without a patch component. system,latest, empty values, interpolations (s"…"/${…}), and multi-line string forms.- Other
*.sbtfiles,project/*.scalabuild definitions, andplugins.sbt. - A
build.propertiesfile outside aproject/directory. - Scala 2.12 and 2.13 (still maintained), current Scala 3 LTS and Next lines, and sbt 1.x / 2.x.
- Vulnerability advisories, license policy, and whether a newer version of a package exists.
- Malformed or oversized files (over 1 MiB, or a line over 4,096 characters) produce nothing, not partial results.
Known limits and false-positive boundaries
build.sbtis read line by line, not as a Scala AST. AscalaVersionthat spans lines, uses a non-string literal, or is computed is not matched.- Cross-building (
crossScalaVersions) is not read. - Monorepos are scanned file by file; findings in nested projects are reported like any other.
Validation
Eighty public repositories at pinned commits cover this detector, chosen blind by the 2026-11-07 rule in Validation. The set includes .scala-version, build.sbt scalaVersion, and project/build.properties sbt.version declaration forms, plus Scala 2.12 / 2.13 / 3.3 pins as zero-finding or no-scala-finding controls (those lines are intentionally not judged). Every expected finding has a maintainer-review note naming the path and line against the Scala development guarantees and sbt download pages.