sbt "unresolved dependency" in CI
sbt asked a resolver for an artifact and got nothing back. Either the coordinates are wrong, the resolver is missing, or the network call to fetch the JAR failed mid-build.
What this error means
Dependency resolution aborts with unresolved dependency: group#artifact;version: not found, often followed by the list of resolvers sbt tried. When the coordinates are real, the failure is usually a transient network or registry hiccup.
[error] (update) sbt.librarymanagement.ResolveException: Error downloading com.example#widget_2.13;1.4.0
[error] Not found
[error] download failed: com.example#widget_2.13;1.4.0!widget_2.13.jarCommon causes
Wrong coordinates or missing Scala suffix
A Scala library is published as widget_2.13, not widget. Omitting the %% operator (which appends the binary version) leaves sbt looking for an artifact that does not exist.
A private resolver is not configured
If the artifact lives in a private Maven repo, CI needs the resolver and credentials. Without them, sbt only checks Maven Central and reports the module as not found.
Transient fetch failure
The coordinates resolve but the JAR download times out or the registry returns 5xx. The same build passes on a re-run.
How to fix it
Confirm the coordinates and operator
- Use
%%for Scala libraries so sbt appends the binary version, and%only for plain Java JARs. - Verify the exact group, artifact, and version exist on the published index.
- Run
sbt updatelocally to reproduce before pushing.
Add the private resolver and credentials
Declare the resolver and supply credentials from CI secrets, not committed files.
resolvers += "Internal" at sys.env("REPO_URL")
credentials += Credentials(
"Repo", "repo.example.com",
sys.env("REPO_USER"), sys.env("REPO_TOKEN"))Re-run if the download itself failed
A bare Not found on valid coordinates is usually transient. On Latchkey managed runners, self-healing auto-retries transient fetch failures so a one-off registry blip does not fail the job.
How to prevent it
- Pin versions and commit a reproducible dependency set.
- Keep resolver URLs and credentials in CI secrets.
- Cache the Coursier/Ivy directory to reduce network fetches.