NoSuchMethodError in Scala 3

Once again, I was making good progress in my migration to Scala 3 (with a workaround to the problem that I posted about recently), and then I was hit with a NoSuchMethodError out of the blue. I tried several clean recompiles to no avail.

My program was working fine, and then I started playing around with some syntax changes just for fun (removing some optional braces), and I was hit with the NoSuchMethodError. The offending line is a simple case class instantiation that was working fine:

val options = TestOptions(args, numArgsReq=1)

Any idea what the problem might be? The stack trace follows. I see something about “reflect”. Is it possible that I am using some reflection that I am not ever aware of? If so, how can I track it down? Thanks.

java.lang.NoSuchMethodError: scala.runtime.ScalaRunTime$.wrapRefArray([Ljava/lang/Object;)Lscala/collection/immutable/ArraySeq;
at trajspec.test.TestOptions$.$lessinit$greater$default$2(TestOptions.scala:13)
at trajspec.test.Resolve1Test$.main(Resolve1Test.scala:28)
at trajspec.test.Resolve1Test.main(Resolve1Test.scala)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at scala.reflect.internal.util.ScalaClassLoader$$anonfun$run$1.apply(ScalaClassLoader.scala:70)
at scala.reflect.internal.util.ScalaClassLoader$class.asContext(ScalaClassLoader.scala:31)
at scala.reflect.internal.util.ScalaClassLoader$URLClassLoader.asContext(ScalaClassLoader.scala:101)
at scala.reflect.internal.util.ScalaClassLoader$class.run(ScalaClassLoader.scala:70)
at scala.reflect.internal.util.ScalaClassLoader$URLClassLoader.run(ScalaClassLoader.scala:101)
at scala.tools.nsc.CommonRunner$class.run(ObjectRunner.scala:22)
at scala.tools.nsc.ObjectRunner$.run(ObjectRunner.scala:39)
at scala.tools.nsc.CommonRunner$class.runAndCatch(ObjectRunner.scala:29)
at scala.tools.nsc.ObjectRunner$.runAndCatch(ObjectRunner.scala:39)
at scala.tools.nsc.MainGenericRunner.runTarget$1(MainGenericRunner.scala:65)
at scala.tools.nsc.MainGenericRunner.run$1(MainGenericRunner.scala:87)
at scala.tools.nsc.MainGenericRunner.process(MainGenericRunner.scala:98)
at scala.tools.nsc.MainGenericRunner$.main(MainGenericRunner.scala:103)
at scala.tools.nsc.MainGenericRunner.main(MainGenericRunner.scala)

Can you crate a MCVE that reproduces the problem on Scastie or in ScalaFiddle?

I have no idea how to do that.

Here’s something fishy. In my toplevel/project directory, I have a file called plugins.sbt which contains this line:

addSbtPlugin(“ch.epfl.lamp” % “sbt-dotty” % “0.5.1”)

But there is a directory under that one, also called project (toplevel/project/project), which also contains a file called plugins.sbt containing this line:

addSbtPlugin(“ch.epfl.lamp” % “sbt-dotty” % “0.4.6”)

I have no idea how I ended up with two versions of that file. Should I delete one of them? Which one is correct? Thanks.

OK, I reverted back to Scala 2.13.4, removed all target directories and did a clean compilation. Now I am still getting a NoSuchMethodError. What the hell could I have possibly done to screw this thing up so badly? This is getting ridiculous. Is it sbt 1.4.6 that is screwed up?

java.lang.NoSuchMethodError: scala.Product.$init$(Lscala/Product;)V
at trajspec.test.Resolve1Test$.(Resolve1Test.scala:24)
at trajspec.test.Resolve1Test.main(Resolve1Test.scala)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at scala.reflect.internal.util.ScalaClassLoader$$anonfun$run$1.apply(ScalaClassLoader.scala:70)
at scala.reflect.internal.util.ScalaClassLoader$class.asContext(ScalaClassLoader.scala:31)
at scala.reflect.internal.util.ScalaClassLoader$URLClassLoader.asContext(ScalaClassLoader.scala:101)
at scala.reflect.internal.util.ScalaClassLoader$class.run(ScalaClassLoader.scala:70)
at scala.reflect.internal.util.ScalaClassLoader$URLClassLoader.run(ScalaClassLoader.scala:101)
at scala.tools.nsc.CommonRunner$class.run(ObjectRunner.scala:22)
at scala.tools.nsc.ObjectRunner$.run(ObjectRunner.scala:39)
at scala.tools.nsc.CommonRunner$class.runAndCatch(ObjectRunner.scala:29)
at scala.tools.nsc.ObjectRunner$.runAndCatch(ObjectRunner.scala:39)
at scala.tools.nsc.MainGenericRunner.runTarget$1(MainGenericRunner.scala:65)
at scala.tools.nsc.MainGenericRunner.run$1(MainGenericRunner.scala:87)
at scala.tools.nsc.MainGenericRunner.process(MainGenericRunner.scala:98)
at scala.tools.nsc.MainGenericRunner$.main(MainGenericRunner.scala:103)
at scala.tools.nsc.MainGenericRunner.main(MainGenericRunner.scala)

Sorry to ask, but do you have a copy of the working code, or better yet, use version control? It’s incredibly helpful for experiments.

Yes, of course I use version control (git). I also routinely make defensive backups of my entire source directory in case I screw something up with git.

I just went back to my latest working version in Scala 2.13.4 and did a clean recompile. I am still getting a NoSuchMethodError:

java.lang.NoSuchMethodError: scala.Product.$init$(Lscala/Product;)V

At this point, it seems fairly clear to me that the problem is not with my source code but rather with my Scala/sbt setup. I even tried going back to sbt version 1.3.8, and that didn’t help.

At this point, I am basically dead in the water. Again I ask, what in the world could cause this problem and what can I do to solve it? Do I need to reinstall sbt? Thanks.

1 Like

The stack trace seems to hint at trajspec.test.Resolve1Test being compiled against a different version of the Scala library than the code depending on it is eventually run against. How does this class enter your project (source code, managed/unmanaged lib,…), how is it compiled and against which Scala version (log output?), how is the app depending on it run and against which Scala library version (log output?, ideally including classpath),…?

What command do you run to get that stack trace?

I think this is a CLASSPATH problem. I need to figure out what CLASSPATH sbt uses for its output.

I having been using a bash script to run my Scala programs and test drivers. It contains the following code:

cd ~/$project
sbt package
if [ $? != 0 ]; then exit $?; fi
sbt test:package
if [ $? != 0 ]; then exit $?; fi
CLASSPATH=`sbt --error 'set showSuccess := false' "export fullClasspath"`
export CLASSPATH=$CLASSPATH:~/$project/target/test-classes

This actually worked for years, but since I tried to migrate to Scala 3 it quit working. It’s probably not the best way of doing things, so what is the right way?

I see that sbt puts its compiled classes into toplevel/target, but there are several subdirectories and jar files in that target directory. Do I have to put those all on my CLASSPATH, or is there a simpler way? Thanks.

The first time I read this, it didn’t click. But I just reread it, and it hit me. The bash script that I use to run my test invokes scala – but a different version than sbt uses to compile! The scala version in my bash executable search path was not the one that sbt uses. Duh!

Here is the offending line in the bash script:

scala $project.test.$1 “${@:2}”

I can make it work for now by changing it to:

~/scala-2.13.4/bin/scala $project.test.$1 “${@:2}”

But I would like to make it so that it continues to work even after I change the scala version that sbt is using. I tried this

sbt “test:run $project.test.$1 "${@:2}"”

But that didn’t work. Anyone know what the correct sbt command is? I can’t seem to find it in the docs. Thanks.

1 Like

There are sbt plugins to package your application.
GitHub - sbt/sbt-native-packager: sbt Native Packager is one Ive, but there might be better alternatives, or ways to use that to generate bash scripts only — for instance makeBashScript:

https://sbt-native-packager.readthedocs.io/en/stable/archetypes/java_app/index.html#settings-tasks

1 Like

What does “didn’t work” mean exactly?

If you want to specify the main class to be run, use runMain instead of run.

Usually I’d expect test scope to contain tests without main methods and without any dependencies to external config, governed by a test framework, though.

1 Like

When I run

sbt “test:run $project.test.$1 “${@:2}””

I get

[error] java.lang.RuntimeException: No main class detected.

And when I run

sbt “test:runMain $project.test.$1 “${@:2}””

I get

[error] java.lang.ClassNotFoundException: trajspec.test.Resolve1Test

My testing methods are perhaps a bit unconventional, but I am not a conventional software developer. Each of my test drivers is a case object with its own “main” method. I am willing to consider other ways, but for now I would just like to get the methods that I have been using for years to work.

All I need for now is a way to get access to the version of scala that sbt used to compile so I can invoke it in a bash script. Given the versatility of sbt, I would think there must be a command for that. Why can’t it just be “sbt scala”?

Can you create a minimal repo that reflects your unconventional test mains?

Then there’s likely no file with path $PROJECT_ROOT/src/test/scala/trajspec/test/Resolve1Test.scala (and neither $PROJECT_ROOT/src/main/scala/trajspec/test/Resolve1Test.scala) in your project…?

Build tools tend to rely heavily on conventions. You don’t have to comply with all of them (it makes life easier, though), but then it’s even more important to understand the expectations of the tool in order to bridge the gap between the tool’s conventions and yours.

sbt downloads and manages the Scala version(s) you have configured in your project. This is done via jar files, i.e. there are no “scala”/“scalac” executables for these.