Skip to content

Accessing a package-private member from an inline method causes NoClassDefFoundError at runtime #24219

@harry0000

Description

@harry0000

This issue is based on the discussion below.

#24216

Compiler version

  • 3.3.7
  • 3.7.2
  • 3.7.3
  • 3.8.0-RC1-bin-20251022-b325681-NIGHTLY

Minimized code

/src/main/scala/foo/Main.scala

package foo

package internal {
  private[foo] def hello(): String = "Hello"
}

inline def greeting(): Unit = {
  val msg = internal.hello()
  println(msg)
}

@main def main(): Unit = {
  greeting()
}

build.sbt

name := "foo"
version := "0.1.0-SNAPSHOT"
scalaVersion := "3.7.3"

Output

[info] running foo.main 
Exception in thread "sbt-bg-threads-1" java.lang.NoClassDefFoundError: foo/internal
        at foo.Main$package$.main(Main.scala:8)
        at foo.main.main(Main.scala:12)
        at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:103)
        at java.base/java.lang.reflect.Method.invoke(Method.java:580)
        at sbt.Run.invokeMain(Run.scala:139)
        at sbt.Run.execute$1(Run.scala:85)
        at sbt.Run.$anonfun$runWithLoader$5(Run.scala:112)
        at sbt.Run$.executeSuccess(Run.scala:227)
        at sbt.Run.runWithLoader(Run.scala:112)
        at sbt.Defaults$.$anonfun$bgRunTask$6(Defaults.scala:2094)
        at sbt.Defaults$.$anonfun$termWrapper$2(Defaults.scala:2033)
        at scala.runtime.java8.JFunction0$mcV$sp.apply(JFunction0$mcV$sp.java:23)
        at scala.util.Try$.apply(Try.scala:213)
        at sbt.internal.BackgroundThreadPool$BackgroundRunnable.run(DefaultBackgroundJobService.scala:378)
        at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1144)
        at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:642)
        at java.base/java.lang.Thread.run(Thread.java:1583)
Caused by: java.lang.ClassNotFoundException: foo.internal
        at java.base/java.net.URLClassLoader.findClass(URLClassLoader.java:445)
        at sbt.internal.ManagedClassLoader.findClass(ManagedClassLoader.java:103)
        at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:593)
        at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:526)
        ... 17 more
[success] Total time: 7 s, completed 2025/10/22 13:44:35

Expectation

The program should run and print Hello.

Workaround

  1. Import the member inside the greeting method and call it unqualified:
inline def greeting(): Unit = {
  import foo.internal.hello
  val msg = hello()
  println(msg)
}
  1. Remove private[foo] visibility from the internal method:
package internal {
  def hello(): String = "Hello"
}

inline def greeting(): Unit = {
  val msg = internal.hello()
  println(msg)
}

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions