Head scratcher.. "java.lang.ClassNotFoundException: kotlin.collections.ArraysKt___ArraysKt"

I have a java webapp and want to introduce kotlin 2.3.0. I migrated my servlets into kotlin, project compiles but during runtime I get this error. The webserver is running tomcat 9 and JDK 17

java.lang.ClassNotFoundException: kotlin.collections.ArraysKt___ArraysKt

Complete stack trace.

Dec 22, 2025 7:11:43 AM org.apache.catalina.core.StandardWrapperValve invoke
SEVERE: Servlet.service() for servlet [plotDataServlet] in context with path [/pqm] threw exception [Servlet execution threw an exception] with root cause
java.lang.ClassNotFoundException: kotlin.collections.ArraysKt___ArraysKt
	at org.apache.catalina.loader.WebappClassLoaderBase.loadClass(WebappClassLoaderBase.java:1354)
	at org.apache.catalina.loader.WebappClassLoaderBase.loadClass(WebappClassLoaderBase.java:1163)
	at java.base/java.lang.ClassLoader.defineClass1(Native Method)
	at java.base/java.lang.ClassLoader.defineClass(ClassLoader.java:1027)
	at java.base/java.security.SecureClassLoader.defineClass(SecureClassLoader.java:150)
	at org.apache.catalina.loader.WebappClassLoaderBase.findClassInternal(WebappClassLoaderBase.java:2342)
	at org.apache.catalina.loader.WebappClassLoaderBase.findClassInternal(WebappClassLoaderBase.java:2216)
	at com.controlj.green.webserver.impl.CustomWebappClassLoader.findClassInternal(CustomWebappClassLoader.java:129)
	at org.apache.catalina.loader.WebappClassLoaderBase.findClass(WebappClassLoaderBase.java:824)
	at org.apache.catalina.loader.WebappClassLoaderBase.loadClass(WebappClassLoaderBase.java:1315)
	at org.apache.catalina.loader.WebappClassLoaderBase.loadClass(WebappClassLoaderBase.java:1163)
	at kotlin.collections.CollectionsKt__CollectionsKt.listOf(Collections.kt:81)
	at dev.dev01.addon.pqm.chart.PlotlyJsonBuilderKt.buildPlotlyJson(PlotlyJsonBuilder.kt:76)
	at dev.dev01.addon.pqm.servlets.PlotDataServlet.doGet(PlotDataServlet.kt:87)
	at javax.servlet.http.HttpServlet.service(HttpServlet.java:529)
	at javax.servlet.http.HttpServlet.service(HttpServlet.java:623)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:199)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:144)
	at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:51)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:168)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:144)
	at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:168)
	at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:90)
	at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:482)
	at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:130)
	at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:93)
	at org.apache.catalina.authenticator.SingleSignOn.invoke(SingleSignOn.java:289)
	at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:74)
	at com.controlj.green.webserver.impl.StandardHeaderValve.invoke(StandardHeaderValve.java:87)
	at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:346)
	at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:397)
	at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:63)
	at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:935)
	at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1826)
	at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:52)
	at org.apache.tomcat.util.threads.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1189)
	at org.apache.tomcat.util.threads.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:658)
	at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:63)
	at java.base/java.lang.Thread.run(Thread.java:1583)


This error is thrown because I’m using listof(“test1”,”test2”, “test3”)" which is part of the standard library but not sure why it throws this error works fine with listof(“test”)

I’ve verified that the kotlin stdlib is packaged in the final war file and I added some diagnostic lines in the servlet. The tomcat server doesn’t have any kotlin libs that would conflict.

here’s my servlet. so the servlet has these println() statements and on initial load of the servlet but it crashes and throws no class def error when it gets to buildPlotlyJson() where I have a function with listof() method called.

....
        val threadCl = Thread.currentThread().contextClassLoader
        val servletCl = this::class.java.classLoader

        println("CLIDS: threadCl=${System.identityHashCode(threadCl)} servletCl=${System.identityHashCode(servletCl)}")
        println("Context classloader: $threadCl")
        println("Servlet classloader: $servletCl")

// resource lookup
        val resourcePath = "kotlin/collections/ArraysKt___ArraysKt.class"
        println("getResource(thread): ${threadCl.getResource(resourcePath)}")
        println("getResource(servlet): ${servletCl.getResource(resourcePath)}")

// check physical file on disk (exploded path)
        val libPath = "C:/WC/programdata/webserver_base/work/TomcatEngine/root/pqm/webapp/WEB-INF/lib"
        java.io.File(libPath).listFiles()?.forEach {
            println("LIB FILE: ${it.name} size=${it.length()} modified=${java.util.Date(it.lastModified())}")
        }

// Error thrown inside buildPlotlyJson() function which has listOf(0,1) 
        val plotlyJson: String = buildPlotlyJson(analogChannelDtos, digitalChannelDtos)
....

Here’s the output, on initial load printed to the console.

Inside doGet
Context classloader: AddOnClassLoader
  context: pqm
  delegate: false
----------> Parent Classloader:
jdk.internal.loader.ClassLoaders$AppClassLoader@70dea4e

Servlet classloader: AddOnClassLoader
  context: pqm
  delegate: false
----------> Parent Classloader:
jdk.internal.loader.ClassLoaders$AppClassLoader@70dea4e

getResource(thread): jar:file:/C:/WC/programdata/webserver_base/work/TomcatEngine/root/pqm/webapp/WEB-INF/lib/kotlin-stdlib-2.3.0.jar!/kotlin/collections/ArraysKt___ArraysKt.class
getResource(servlet): jar:file:/C:/WC/programdata/webserver_base/work/TomcatEngine/root/pqm/webapp/WEB-INF/lib/kotlin-stdlib-2.3.0.jar!/kotlin/collections/ArraysKt___ArraysKt.class
LIB FILE: annotations-13.0.jar size=17536 modified=Mon Dec 22 07:11:35 PST 2025
LIB FILE: error_prone_annotations-2.41.0.jar size=20389 modified=Mon Dec 22 07:11:35 PST 2025
LIB FILE: gson-2.13.2.jar size=289901 modified=Mon Dec 22 07:11:35 PST 2025
LIB FILE: htmx.org-2.0.8.jar size=233384 modified=Mon Dec 22 07:11:35 PST 2025
LIB FILE: jstl-1.2.jar size=414240 modified=Mon Dec 22 07:11:35 PST 2025
LIB FILE: kotlin-stdlib-2.3.0.jar size=1796996 modified=Mon Dec 22 07:11:35 PST 2025
LIB FILE: kotlin-stdlib-jdk7-2.3.0.jar size=946 modified=Mon Dec 22 07:11:35 PST 2025
LIB FILE: kotlin-stdlib-jdk8-2.3.0.jar size=952 modified=Mon Dec 22 07:11:35 PST 2025
LIB FILE: picocss__pico-2.1.1.jar size=2891622 modified=Mon Dec 22 07:11:35 PST 2025
LIB FILE: plotly.js-dist-min-3.0.1.jar size=1416657 modified=Mon Dec 22 07:11:35 PST 2025
LIB FILE: pqm-0.0.1.jar size=1093157 modified=Mon Dec 22 07:11:35 PST 2025

 

but then when I resend adoGet() request the same servlet. and I get null when it tries to find the ArrowsKt class and the stack trace is thrown.

Inside doGet
CLIDS: threadCl=2055081295 servletCl=2055081295
Context classloader: AddOnClassLoader
  context: pqm
  delegate: false
----------> Parent Classloader:
jdk.internal.loader.ClassLoaders$AppClassLoader@70dea4e

Servlet classloader: AddOnClassLoader
  context: pqm
  delegate: false
----------> Parent Classloader:
jdk.internal.loader.ClassLoaders$AppClassLoader@70dea4e

getResource(thread): null
getResource(servlet): null
LIB FILE: annotations-13.0.jar size=17536 modified=Mon Dec 22 07:11:35 PST 2025
LIB FILE: error_prone_annotations-2.41.0.jar size=20389 modified=Mon Dec 22 07:11:35 PST 2025
LIB FILE: gson-2.13.2.jar size=289901 modified=Mon Dec 22 07:11:35 PST 2025
LIB FILE: htmx.org-2.0.8.jar size=233384 modified=Mon Dec 22 07:11:35 PST 2025
LIB FILE: jstl-1.2.jar size=414240 modified=Mon Dec 22 07:11:35 PST 2025
LIB FILE: kotlin-stdlib-2.3.0.jar size=1796996 modified=Mon Dec 22 07:11:35 PST 2025
LIB FILE: kotlin-stdlib-jdk7-2.3.0.jar size=946 modified=Mon Dec 22 07:11:35 PST 2025
LIB FILE: kotlin-stdlib-jdk8-2.3.0.jar size=952 modified=Mon Dec 22 07:11:35 PST 2025
LIB FILE: picocss__pico-2.1.1.jar size=2891622 modified=Mon Dec 22 07:11:35 PST 2025
LIB FILE: plotly.js-dist-min-3.0.1.jar size=1416657 modified=Mon Dec 22 07:11:35 PST 2025
LIB FILE: pqm-0.0.1.jar size=1093157 modified=Mon Dec 22 07:11:35 PST 2025

Something happens when listof() is called crashes and burns. what’s weird is I can debug the app and I can use listof(“test”) but I can’t use listof(“test1”,”test2”)

How are you building your app? Using Maven/Gradle, or just doing it all yourself?

Have you tried creating a shaded jar instead of a war?

This definitely seems like a weird problem… like the class loader just loses the Kotlin files at runtime.

It’s build with maven, I also did a small project in gradle 9 yesterday just to test and it also has the same behavior. mapof() is fine listof(“test1”) is fine but listof(“test1”, “test2”) is not.

the maven build process does create a shaded jar, all the deps are in the WEB-INF\lib\ folder for the .war archive. At the end you get a large 6mb war file when you add in kotlin stdlibrary and other deps.

As a workaround, I’m having to use Arrays.asList() in kotlin from java.util.Arrays and it works fine. Just something about listof(1,2,3,4,5,6) just breaks things.

So after further testing. if I use Arrays.asList(“test1”,”test2”) from java.util package and I still monitor the servlet class loader, each execution still shows the ArraysKt.class on the class path, each one of these sections below is the console output and a seprate doGet() request to the servlet.

getResource(thread): jar:file:/C:/WC/programdata/webserver_base/work/TomcatEngine/root/pqmwaveform/webapp/WEB-INF/lib/kotlin-stdlib-2.3.0.jar!/kotlin/collections/ArraysKt___ArraysKt.class
getResource(servlet): jar:file:/C:/WC/programdata/webserver_base/work/TomcatEngine/root/pqmwaveform/webapp/WEB-INF/lib/kotlin-stdlib-2.3.0.jar!/kotlin/collections/ArraysKt___ArraysKt.class
LIB FILE: annotations-13.0.jar size=17536 modified=Tue Dec 23 12:40:10 PST 2025
LIB FILE: gson-2.10.1.jar size=283367 modified=Tue Dec 23 12:40:10 PST 2025
LIB FILE: htmx.org-2.0.8.jar size=233384 modified=Tue Dec 23 12:40:10 PST 2025
LIB FILE: jstl-1.2.jar size=414240 modified=Tue Dec 23 12:40:10 PST 2025
LIB FILE: kotlin-stdlib-2.3.0.jar size=1796996 modified=Tue Dec 23 12:40:10 PST 2025
LIB FILE: picocss__pico-2.1.1.jar size=2891622 modified=Tue Dec 23 12:40:10 PST 2025
LIB FILE: plotly.js-dist-min-3.0.1.jar size=1416657 modified=Tue Dec 23 12:40:10 PST 2025
Inside doGet
CLIDS: threadCl=473511298 servletCl=473511298
Context classloader: AddOnClassLoader
  context: pqmwaveform
  delegate: false
----------> Parent Classloader:
jdk.internal.loader.ClassLoaders$AppClassLoader@70dea4e

Servlet classloader: AddOnClassLoader
  context: pqmwaveform
  delegate: false
----------> Parent Classloader:
jdk.internal.loader.ClassLoaders$AppClassLoader@70dea4e

getResource(thread): jar:file:/C:/WWC/programdata/webserver_base/work/TomcatEngine/root/pqmwaveform/webapp/WEB-INF/lib/kotlin-stdlib-2.3.0.jar!/kotlin/collections/ArraysKt___ArraysKt.class
getResource(servlet): jar:file:/C:/WC/programdata/webserver_base/work/TomcatEngine/root/pqmwaveform/webapp/WEB-INF/lib/kotlin-stdlib-2.3.0.jar!/kotlin/collections/ArraysKt___ArraysKt.class
LIB FILE: annotations-13.0.jar size=17536 modified=Tue Dec 23 12:40:10 PST 2025
LIB FILE: gson-2.10.1.jar size=283367 modified=Tue Dec 23 12:40:10 PST 2025
LIB FILE: htmx.org-2.0.8.jar size=233384 modified=Tue Dec 23 12:40:10 PST 2025
LIB FILE: jstl-1.2.jar size=414240 modified=Tue Dec 23 12:40:10 PST 2025
LIB FILE: kotlin-stdlib-2.3.0.jar size=1796996 modified=Tue Dec 23 12:40:10 PST 2025
LIB FILE: picocss__pico-2.1.1.jar size=2891622 modified=Tue Dec 23 12:40:10 PST 2025
LIB FILE: plotly.js-dist-min-3.0.1.jar size=1416657 modified=Tue Dec 23 12:40:10 PST 2025
Inside doGet
CLIDS: threadCl=473511298 servletCl=473511298
Context classloader: AddOnClassLoader
  context: pqmwaveform
  delegate: false
----------> Parent Classloader:
jdk.internal.loader.ClassLoaders$AppClassLoader@70dea4e

Servlet classloader: AddOnClassLoader
  context: pqmwaveform
  delegate: false
----------> Parent Classloader:
jdk.internal.loader.ClassLoaders$AppClassLoader@70dea4e

getResource(thread): jar:file:/C:/WC/programdata/webserver_base/work/TomcatEngine/root/pqmwaveform/webapp/WEB-INF/lib/kotlin-stdlib-2.3.0.jar!/kotlin/collections/ArraysKt___ArraysKt.class
getResource(servlet): jar:file:/C:/WC/programdata/webserver_base/work/TomcatEngine/root/pqmwaveform/webapp/WEB-INF/lib/kotlin-stdlib-2.3.0.jar!/kotlin/collections/ArraysKt___ArraysKt.class
LIB FILE: annotations-13.0.jar size=17536 modified=Tue Dec 23 12:40:10 PST 2025
LIB FILE: gson-2.10.1.jar size=283367 modified=Tue Dec 23 12:40:10 PST 2025
LIB FILE: htmx.org-2.0.8.jar size=233384 modified=Tue Dec 23 12:40:10 PST 2025
LIB FILE: jstl-1.2.jar size=414240 modified=Tue Dec 23 12:40:10 PST 2025
LIB FILE: kotlin-stdlib-2.3.0.jar size=1796996 modified=Tue Dec 23 12:40:10 PST 2025
LIB FILE: picocss__pico-2.1.1.jar size=2891622 modified=Tue Dec 23 12:40:10 PST 2025
LIB FILE: plotly.js-dist-min-3.0.1.jar size=1416657 modified=Tue Dec 23 12:40:10 PST 2025

However, as soon as I use listof(“test12”,”test1233”) the console output shows null after the listof() method is invoked. So strange and ArraysKt.class disappears from the classpath.

What if you try going back to Kotlin 2.2.0? I’m thinking this might be a specific bug in 2.3.0.

I’ve tried this also. I went to 2.2.0, and even went down to 1.9.0 and lower versions, all have this issue. I also tried the jdk8 kotlin std library and no change.

Do you wanna post up your small Gradle project? I’d be interested in seeing if I can replicate the problem on my PC.

Also what JDK are you using? And I don’t mean 17 or 21 or whatever, I mean what vendor; Temurin, Semuru, something else?