SBT complains about unresolved dependencies for multi-module projects
Or how I learnt a bit more SBT, and continue to be mildly disgruntled by the bomb
Motivation:
I’ve wanted to write that “awesome Scala project” for a while now but have been constantly sidetracked by other projects which were more interesting. Since my current project at work doesn’t use Scala, it’s that much harder to fire up SBT and wait for the Universe to download and build before I can get productive (Incidentally, SBT is a bit faster than what I can remember, so it’s probably only downloading about half the Universe now).
I wrote one module of my project and pushed it to Github, and decided that I’d use Travis CI to build it, like I’ve used it in several projects before. That’s when the reason why I dislike comprehensive “shell-in-a-shell” build tools like SBT came rushing in. Whenever a language or build tool encourages using the build tool itself to run your project, I get annoyed. I don’t plan to run from source in the live environment, and having to run commands like sbt run
instead of java -jar jarhere.jar
worries me. I want the build tool to be just that - build my project. I understand that it’s a matter of personal choice and that I could build the project and run it using java -jar
, it annoys me that there are a hundred different tutorials that talk about using sbt run
but I really have to dig deep to find one that tells me (unambiguously) how to package and run a Jar.
Anyway, the problem was this - what was compiling just fine in my IDE, and what ran just fine inside SBT, was now breaking in Travis CI when I ran the sbt test
command. This is what I got:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
x@y:~/project$ sbt test
[info] Loading project definition from /xyz/project
[info] Set current project to projectxyz (in build file:/xyz/)
[info] Updating {file:/xyz/}core...
[info] Resolving common#common_2.12;0.1-SNAPSHOT ...
[warn] module not found: common#common_2.12;0.1-SNAPSHOT
[warn] ==== local: tried
[warn] /home/x/.ivy2/local/common/common_2.12/0.1-SNAPSHOT/ivys/ivy.xml
[warn] ==== public: tried
[warn] https://repo1.maven.org/maven2/common/common_2.12/0.1-SNAPSHOT/common_2.12-0.1-SNAPSHOT.pom
[warn] ==== local-preloaded-ivy: tried
[warn] /home/x/.sbt/preloaded/common/common_2.12/0.1-SNAPSHOT/ivys/ivy.xml
[warn] ==== local-preloaded: tried
[warn] file:////home/x/.sbt/preloaded/common/common_2.12/0.1-SNAPSHOT/common_2.12-0.1-SNAPSHOT.pom
[info] Resolving jline#jline;2.14.4 ...
[warn] ::::::::::::::::::::::::::::::::::::::::::::::
[warn] :: UNRESOLVED DEPENDENCIES ::
[warn] ::::::::::::::::::::::::::::::::::::::::::::::
[warn] :: common#common_2.12;0.1-SNAPSHOT: not found
[warn] ::::::::::::::::::::::::::::::::::::::::::::::
[warn]
[warn] Note: Unresolved dependencies path:
[warn] common:common_2.12:0.1-SNAPSHOT
[warn] +- core:core_2.12:1.0
sbt.ResolveException: unresolved dependency: common#common_2.12;0.1-SNAPSHOT: not found
at sbt.IvyActions$.sbt$IvyActions$$resolve(IvyActions.scala:313)
at sbt.IvyActions$$anonfun$updateEither$1.apply(IvyActions.scala:191)
at sbt.IvyActions$$anonfun$updateEither$1.apply(IvyActions.scala:168)
at sbt.IvySbt$Module$$anonfun$withModule$1.apply(Ivy.scala:156)
at sbt.IvySbt$Module$$anonfun$withModule$1.apply(Ivy.scala:156)
at sbt.IvySbt$$anonfun$withIvy$1.apply(Ivy.scala:133)
at sbt.IvySbt.sbt$IvySbt$$action$1(Ivy.scala:57)
at sbt.IvySbt$$anon$4.call(Ivy.scala:65)
at xsbt.boot.Locks$GlobalLock.withChannel$1(Locks.scala:93)
at xsbt.boot.Locks$GlobalLock.xsbt$boot$Locks$GlobalLock$$withChannelRetries$1(Locks.scala:78)
at xsbt.boot.Locks$GlobalLock$$anonfun$withFileLock$1.apply(Locks.scala:97)
at xsbt.boot.Using$.withResource(Using.scala:10)
at xsbt.boot.Using$.apply(Using.scala:9)
at xsbt.boot.Locks$GlobalLock.ignoringDeadlockAvoided(Locks.scala:58)
at xsbt.boot.Locks$GlobalLock.withLock(Locks.scala:48)
at xsbt.boot.Locks$.apply0(Locks.scala:31)
at xsbt.boot.Locks$.apply(Locks.scala:28)
at sbt.IvySbt.withDefaultLogger(Ivy.scala:65)
at sbt.IvySbt.withIvy(Ivy.scala:128)
at sbt.IvySbt.withIvy(Ivy.scala:125)
at sbt.IvySbt$Module.withModule(Ivy.scala:156)
at sbt.IvyActions$.updateEither(IvyActions.scala:168)
at sbt.Classpaths$$anonfun$sbt$Classpaths$$work$1$1.apply(Defaults.scala:1541)
at sbt.Classpaths$$anonfun$sbt$Classpaths$$work$1$1.apply(Defaults.scala:1537)
at sbt.Classpaths$$anonfun$doWork$1$1$$anonfun$121.apply(Defaults.scala:1572)
at sbt.Classpaths$$anonfun$doWork$1$1$$anonfun$121.apply(Defaults.scala:1570)
at sbt.Tracked$$anonfun$lastOutput$1.apply(Tracked.scala:37)
at sbt.Classpaths$$anonfun$doWork$1$1.apply(Defaults.scala:1575)
at sbt.Classpaths$$anonfun$doWork$1$1.apply(Defaults.scala:1569)
at sbt.Tracked$$anonfun$inputChanged$1.apply(Tracked.scala:60)
at sbt.Classpaths$.cachedUpdate(Defaults.scala:1592)
at sbt.Classpaths$$anonfun$updateTask$1.apply(Defaults.scala:1519)
at sbt.Classpaths$$anonfun$updateTask$1.apply(Defaults.scala:1471)
at scala.Function1$$anonfun$compose$1.apply(Function1.scala:47)
at sbt.$tilde$greater$$anonfun$$u2219$1.apply(TypeFunctions.scala:40)
at sbt.std.Transform$$anon$4.work(System.scala:63)
at sbt.Execute$$anonfun$submit$1$$anonfun$apply$1.apply(Execute.scala:228)
at sbt.Execute$$anonfun$submit$1$$anonfun$apply$1.apply(Execute.scala:228)
at sbt.ErrorHandling$.wideConvert(ErrorHandling.scala:17)
at sbt.Execute.work(Execute.scala:237)
at sbt.Execute$$anonfun$submit$1.apply(Execute.scala:228)
at sbt.Execute$$anonfun$submit$1.apply(Execute.scala:228)
at sbt.ConcurrentRestrictions$$anon$4$$anonfun$1.apply(ConcurrentRestrictions.scala:159)
at sbt.CompletionService$$anon$2.call(CompletionService.scala:28)
at java.util.concurrent.FutureTask.run(FutureTask.java:266)
at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511)
at java.util.concurrent.FutureTask.run(FutureTask.java:266)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
at java.lang.Thread.run(Thread.java:748)
[error] (core/*:update) sbt.ResolveException: unresolved dependency: common#common_2.12;0.1-SNAPSHOT: not found
[error] Total time: 5 s, completed Aug 16, 2017 7:05:59 AM
Searching for “sbt unresolved dependencies” was not very useful. So I dug deeper and found the issue.
Missing build.sbt file, and different version in the root build.sbt
I sometimes need things to be spelled in caps and in a very large font to catch my attention :) While the rest of my modules had an explicit build.sbt
file in the nested structure:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
.
+-- build.sbt
+-- common
\-- src
\-- main
\-- scala
\-- com
\-- caffinc
\-- xyz
+-- core
+-- build.sbt
\-- src
\-- main
\-- scala
\-- com
\-- caffinc
\-- xyz
+-- project
+-- build.properties
\-- plugins.sbt
+-- target
\-- web
+-- app
\-- com
\-- caffinc
\-- xyz
+-- build.sbt
\-- conf
My common
project did not have a build.sbt
. In my root build.sbt
, the core
project depends on the common
project:
1
2
3
4
5
6
7
8
9
10
11
12
13
name := "xyz"
version := "0.1"
scalaVersion := "2.12.3"
lazy val common = project
lazy val core = project
.dependsOn(common)
lazy val web = project
.dependsOn(common)
My core/build.sbt
looks like this:
1
2
3
4
5
6
7
version := "1.0"
scalaVersion := "2.12.3"
libraryDependencies ++= Seq(
"org.apache.kafka" %% "kafka" % "0.11.0.0"
)
I went ahead and added an explicit build.sbt
for common
, and this fixed my build issues. I changed the version in my root build.sbt
to “1.0” cause whoops.
TL;DR
Check your damn root build.sbt
file’s version
entry. Add an explicit build.sbt
inside your sub-modules.
I hope this helps someone out there who’s trying to come to terms with SBT
!