beginners

Doug Harvey 2025-05-23T03:10:27.074349Z

Hello, I am getting the following error

java -jar target/api-server-0.0.1-standalone.jar
hello
Exception in thread "main" java.lang.NoSuchMethodError: 'java.util.concurrent.ExecutorService java.util.concurrent.Executors.newVirtualThreadPerTaskExecutor()'
	at org.httpkit.utils$new_worker$fn__12630.invoke(utils.clj:69)
	at org.httpkit.utils$new_worker.invokeStatic(utils.clj:77)
	at org.httpkit.utils$new_worker.invoke(utils.clj:46)
	at org.httpkit.server$new_worker.invokeStatic(server.clj:63)
	at org.httpkit.server$new_worker.invoke(server.clj:54)
	at org.httpkit.server$run_server.invokeStatic(server.clj:162)
	at org.httpkit.server$run_server.doInvoke(server.clj:79)
	at clojure.lang.RestFn.invoke(RestFn.java:426)
	at io.pedestal.http.http_kit$create_connector$reify__13389.start_connector_BANG_(http_kit.clj:112)
	at io.pedestal.connector$start_BANG_.invokeStatic(connector.clj:164)
	at io.pedestal.connector$start_BANG_.invoke(connector.clj:157)
	at main$_main.invokeStatic(main.clj:34)
	at main$_main.invoke(main.clj:32)
	at clojure.lang.AFn.applyToHelper(AFn.java:152)
	at clojure.lang.AFn.applyTo(AFn.java:144)
	at main.main(Unknown Source)
I am trying to build an api service using pedestal. The only source file right now is src/main.clj
(ns main
  (:require [io.pedestal.connector :as conn]
            [io.pedestal.http.http-kit :as hk]
            [io.pedestal.http.route :as route])
  (:gen-class))

(defn response [status body & {:as headers}]
  {:status status :body body :headers headers})

(def ok (partial response 200))

(def created (partial response 201))

(def accepted (partial response 202))

(def echo
  {:name :echo
   :enter
   (fn [context]
     (let [request (:request context)
           response (ok request)]
       (assoc context :response response)))})

(def routes
  #{["/"     :get echo ]})

(defn create-connector []
  (-> (conn/default-connector-map 8890)
      (conn/with-default-interceptors)
      (hk/create-connector nil)))

(defn -main []
  (println "hello")
  (conn/start! (create-connector)))
If I comment out the (conn/start! in -main it works fine. If start clj and run
(require 'main)
(main/-main)
it works fine as well. My deps.edn is
{:paths ["src"]
 :deps  {io.pedestal/pedestal.jetty    {:mvn/version "0.8.0-SNAPSHOT"}
         io.pedestal/pedestal.http-kit {:mvn/version "0.8.0-SNAPSHOT"}
         org.clojure/data.json         {:mvn/version "2.5.1"}
         org.slf4j/slf4j-simple        {:mvn/version "2.0.17"}
         com.novemberain/monger        {:mvn/version "3.6.0"}
        }

 :aliases {
           :build {
                   :deps {io.github.clojure/tools.build {:mvn/version "0.10.9"}}
                   :ns-default build}}
 }
does this mean that my :deps is missing something? Is there a way to start up clj so it only uses libraries that are named in deps.edn? thanks for any suggestions

Doug Harvey 2025-05-23T11:42:51.751279Z

ok, thanks.

java -version
openjdk version "17.0.3" 2022-04-19 LTS
OpenJDK Runtime Environment Corretto-17.0.3.6.1 (build 17.0.3+6-LTS)
OpenJDK 64-Bit Server VM Corretto-17.0.3.6.1 (build 17.0.3+6-LTS, mixed mode, sharing)
doug@mac-studio api-server-keep> clj
Clojure 1.12.0
user=> (System/getProperty "java.version")
"23"
user=>
I'm on a mac, I installed clj with homebrew, it is
#!/bin/bash
JAVA_HOME="${JAVA_HOME:-/opt/homebrew/opt/openjdk/libexec/openjdk.jdk/Contents/Home}" exec "/opt/homebrew/Cellar/clojure/1.12.0.1479/libexec/bin/clj"  "$@"
If I use that version of java to run the jar there are no errors. and this also works:
JAVA_HOME=/usr/bin clj -T:build uber
Downloading: io/pedestal/pedestal.jetty/0.8.0-SNAPSHOT/maven-metadata.xml from clojars
Downloading: io/pedestal/pedestal.http-kit/0.8.0-SNAPSHOT/maven-metadata.xml from clojars
Downloading: io/pedestal/pedestal.log/0.8.0-SNAPSHOT/maven-metadata.xml from clojars
Downloading: io/pedestal/pedestal.service/0.8.0-SNAPSHOT/maven-metadata.xml from clojars
Downloading: io/pedestal/pedestal.servlet/0.8.0-SNAPSHOT/maven-metadata.xml from clojars
Downloading: io/pedestal/pedestal.route/0.8.0-SNAPSHOT/maven-metadata.xml from clojars
Downloading: io/pedestal/pedestal.telemetry/0.8.0-SNAPSHOT/maven-metadata.xml from clojars
Downloading: io/pedestal/pedestal.interceptor/0.8.0-SNAPSHOT/maven-metadata.xml from clojars
Downloading: io/pedestal/pedestal.common/0.8.0-SNAPSHOT/maven-metadata.xml from clojars
Build folder "target" removed
Uber file created: "target/api-server-0.0.1-standalone.jar"

java -jar target/api-server-0.0.1-standalone.jar
hello
[ pedestal started and waiting ]
thank you very much for the help.

dpsutton 2025-05-23T14:03:43.371879Z

one more followup. do you remember how you installed the clojure cli tools with homebrew? My memory is that there’s an easy to find one that has its own dependency on a jvm, and then there’s the officially supported one, maybe a tap(?), that removes this dependency on a particular jvm. The result is that if you get the “easy” one, you end up in a weird situation like this where you can easily miss that there are two different jvm versions running. I think this subtle bug is probably the clearest distillation of why that “easy” brew installation is annoyingly a bit user hostile

2025-05-23T03:35:16.627569Z

You are trying to use an http kit that was aot compiled on java with virtual threads on a version of java without virtual threads

2025-05-23T03:36:28.903369Z

Http kit tries to sniff the availability of virtual threads, but does it at macro expansion time, so aot classes have the behavior fixed by whatever they were compiled on

2025-05-23T03:38:15.301539Z

Http kit, as far as I know, doesn't distribute aot jars, so that means either you have stale classes somewhere, or one of your other deps is including aot'ed http kit their jar (gross)

2025-05-23T03:43:17.602989Z

Ah, bet it is pedestal, you'd hope a nubank/cognitect connected project wouldn't be packaged so poorly

dpsutton 2025-05-23T03:54:26.893969Z

i’m not seeing any class files from http kit there

dpsutton 2025-05-23T03:55:21.440619Z

clj -Sdeps '{:deps  {io.pedestal/pedestal.jetty    {:mvn/version "0.8.0-SNAPSHOT"}
         io.pedestal/pedestal.http-kit {:mvn/version "0.8.0-SNAPSHOT"}
         org.clojure/data.json         {:mvn/version "2.5.1"}
         org.slf4j/slf4j-simple        {:mvn/version "2.0.17"}
         com.novemberain/monger        {:mvn/version "3.6.0"}
        }}'
user=> (enumeration-seq (.getResources (.getContextClassLoader (Thread/currentThread)) "org/httpkit/utils.clj"))
(#object[java.net.URL 0x24b4d544 "jar:file:/Users/dan/.m2/repository/http-kit/http-kit/2.9.0-alpha4/http-kit-2.9.0-alpha4.jar!/org/httpkit/utils.clj"])
user=> (enumeration-seq (.getResources (.getContextClassLoader (Thread/currentThread)) "org/httpkit/utils.class"))
nil

dpsutton 2025-05-23T03:58:50.331679Z

but there’s the call

user=> (source org.httpkit.utils/new-worker)
(defn new-worker
...
(let [;; Calculate at runtime to prevent Graal issues
        n-cores (.availableProcessors (Runtime/getRuntime))
        new-virtual-pool
        (compile-if (Thread/ofVirtual)
          (fn [] (java.util.concurrent.Executors/newVirtualThreadPerTaskExecutor))
          nil)]
any chance the java version when you made your jar is different than the java version running the jar? Maybe @hiredman’s diagnosis is correct but it’s your uberjarring that is the culprit

2025-05-23T04:02:28.705319Z

Oh, yeah, missed that, yeah you are aot compiling using a version of java that supports virtual threads then trying to run the jar on a version that doesn't

dpsutton 2025-05-23T04:03:07.642639Z

can you run

❯ java -version
openjdk version "21.0.2" 2024-01-16 LTS
OpenJDK Runtime Environment Temurin-21.0.2+13 (build 21.0.2+13-LTS)
OpenJDK 64-Bit Server VM Temurin-21.0.2+13 (build 21.0.2+13-LTS, mixed mode)
and then from clj
user=> (System/getProperty "java.version")
"21.0.2"

Doug Harvey 2025-05-24T13:57:07.617839Z

I can't remember how / when I installed clj with homebrew. I will look around to see if there is a more official one. thanks again for the assistance.