This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2024-03-23
Channels
- # babashka (15)
- # beginners (102)
- # biff (4)
- # calva (15)
- # cider (51)
- # clojure (5)
- # clojure-dev (3)
- # clojure-europe (3)
- # clojure-france (1)
- # clojure-india (1)
- # clojure-korea (2)
- # clojure-norway (13)
- # clojurescript (20)
- # data-science (1)
- # datalevin (6)
- # datascript (2)
- # emacs (3)
- # events (2)
- # fulcro (4)
- # gratitude (2)
- # introduce-yourself (8)
- # lsp (3)
- # malli (1)
- # meander (1)
- # nbb (9)
- # off-topic (11)
- # releases (1)
- # ring (1)
- # yamlscript (5)
Hi everybody, I upgraded to the latest cider and I can't start my javafx application anymore. Stacktrace on the 🧵
Exception in thread "JavaFX Application Thread" java.lang.NoClassDefFoundError: Could not initialize class javafx.stage.Screen
at com.sun.javafx.tk.quantum.QuantumToolkit.initSceneGraph(QuantumToolkit.java:331)
at com.sun.javafx.tk.quantum.QuantumToolkit.runToolkit(QuantumToolkit.java:374)
at com.sun.javafx.tk.quantum.QuantumToolkit.lambda$startup$10(QuantumToolkit.java:290)
at com.sun.glass.ui.Application.lambda$run$1(Application.java:155)
at com.sun.glass.ui.gtk.GtkApplication._runLoop(Native Method)
at com.sun.glass.ui.gtk.GtkApplication.lambda$runLoop$10(GtkApplication.java:263)
at java.base/java.lang.Thread.run(Thread.java:1583)
Caused by: java.lang.ExceptionInInitializerError: Exception java.lang.IllegalStateException: This operation is permitted on the event thread only; currentThread = clojure-agent-send-off-pool-0 [in thread "clojure-agent-send-off-pool-0"]
at com.sun.glass.ui.Application.checkEventThread(Application.java:447)
at com.sun.glass.ui.Screen.setEventHandler(Screen.java:367)
at com.sun.javafx.tk.quantum.QuantumToolkit.setScreenConfigurationListener(QuantumToolkit.java:743)
at javafx.stage.Screen.<clinit>(Screen.java:74)
at java.base/java.lang.Class.forName0(Native Method)
at java.base/java.lang.Class.forName(Class.java:421)
at java.base/java.lang.Class.forName(Class.java:412)
at orchard.java$class_info_STAR_$fn__5507.invoke(java.clj:325)
at orchard.java$class_info_STAR_.invokeStatic(java.clj:325)
at orchard.java$class_info_STAR_.invoke(java.clj:321)
at orchard.java$class_info.invokeStatic(java.clj:376)
at orchard.java$class_info.invoke(java.clj:368)
at cider.nrepl$warmup_orchard_caches_BANG_.invokeStatic(nrepl.clj:71)
at cider.nrepl$warmup_orchard_caches_BANG_.invoke(nrepl.clj:53)
at cider.nrepl$fn__6301.invokeStatic(nrepl.clj:77)
at cider.nrepl$fn__6301.invoke(nrepl.clj:76)
at clojure.core$binding_conveyor_fn$fn__5852.invoke(core.clj:2047)
at clojure.lang.AFn.call(AFn.java:18)
at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:317)
at java.base/java.ut
looks like this cider.nrepl$warmup_orchard_caches_BANG_
is doing something that can only be done in a javafx thread
maybe related to this? https://github.com/clojure-emacs/cider-nrepl/issues/842
rolling back to 20231025.508 which uses cider-nrepl "0.41.0" doesn't show this problem
This Orchard call is the culprit as it performs class initialization https://github.com/clojure-emacs/orchard/blob/97c04e67bfd4183adf882b42829da0981d4c0828/src/orchard/java.clj#L325-L328 It's very old code, I'm surprised it didn't fail sooner Fix soon
LMK if this fixes it :) https://clojars.org/cider/cider-nrepl/versions/0.47.1
hey, thanks @U45T93RA6, I'll try it right away
hmmm, still the same error :
;; Startup: /usr/local/bin/clojure -Sdeps \{\:deps\ \{nrepl/nrepl\ \{\:mvn/version\ \"1.1.1\"\}\ cider/cider-nrepl\ \{\:mvn/version\ \"0.47.1\"\}\ refactor-nrepl/refactor-nrepl\ \{\:mvn/version\ \"3.10.0\"\}\}\ \:aliases\ \{\:cider/nrepl\ \{\:main-opts\ \[\"-m\"\ \"nrepl.cmdline\"\ \"--middleware\"\ \"\[refactor-nrepl.middleware/wrap-refactor\,cider.nrepl/cider-middleware\]\"\]\}\}\} -M:dev:dev-tools:storm:cider/nrepl
Mar 24, 2024 6:23:46 PM com.sun.javafx.application.PlatformImpl startup
WARNING: Unsupported JavaFX configuration: classes were loaded from 'unnamed module @b121a86'
Exception in thread "JavaFX Application Thread" java.lang.NoClassDefFoundError: Could not initialize class javafx.stage.Screen
at com.sun.javafx.tk.quantum.QuantumToolkit.initSceneGraph(QuantumToolkit.java:331)
at com.sun.javafx.tk.quantum.QuantumToolkit.runToolkit(QuantumToolkit.java:374)
at com.sun.javafx.tk.quantum.QuantumToolkit.lambda$startup$10(QuantumToolkit.java:290)
at com.sun.glass.ui.Application.lambda$run$1(Application.java:155)
at com.sun.glass.ui.gtk.GtkApplication._runLoop(Native Method)
at com.sun.glass.ui.gtk.GtkApplication.lambda$runLoop$10(GtkApplication.java:263)
at java.base/java.lang.Thread.run(Thread.java:1583)
Caused by: java.lang.ExceptionInInitializerError: Exception java.lang.IllegalStateException: This operation is permitted on the event thread only; currentThread = clojure-agent-send-off-pool-0 [in thread "clojure-agent-send-off-pool-0"]
at com.sun.glass.ui.Application.checkEventThread(Application.java:447)
at com.sun.glass.ui.Screen.setEventHandler(Screen.java:367)
at com.sun.javafx.tk.quantum.QuantumToolkit.setScreenConfigurationListener(QuantumToolkit.java:743)
at javafx.stage.Screen.<clinit>(Screen.java:74)
at java.base/java.lang.Class.forName0(Native Method)
at java.base/java.lang.Class.forName(Class.java:421)
at java.base/java.lang.Class.forName(Class.java:412)
at orchard.java$class_info_STAR_$fn__5507.invoke(java.clj:326)
at orchard.java$class_info_STAR_.invokeStatic(java.clj:325)
at orchard.java$class_info_STAR_.invoke(java.clj:321)
at orchard.java$class_info.invokeStatic(java.clj:378)
at orchard.java$class_info.invoke(java.clj:370)
at cider.nrepl$warmup_orchard_caches_BANG_.invokeStatic(nrepl.clj:71)
at cider.nrepl$warmup_orchard_caches_BANG_.invoke(nrepl.clj:53)
at cider.nrepl$fn__6301.invokeStatic(nrepl.clj:77)
at cider.nrepl$fn__6301.invoke(nrepl.clj:76)
at clojure.core$binding_conveyor_fn$fn__5852.invoke(core.clj:2047)
at clojure.lang.AFn.call(AFn.java:18)
at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:317)
at java.base/java.ut
thanks! I had added a catch NoClassDefFoundError
, I should have added ExceptionInInitializerError
instead/also
New release tomorrow, thanks for your help
np, thank you for looking at it! Let me know and I can try it from github so you don't need to release stuff to Clojars
sure! repeat https://github.com/clojure-emacs/orchard/pull/234 catching the additional class. follow the make install
instructions first for Orchard, then for cider-nrepl (in that order, and following each readme's notes)
thanks 🤝
great, I'll try it and let you know
@U45T93RA6 This ended up being much harder than I expected, so giving up for today. It feels to me like it has to do with some classloders and when static initializers run issues, but not sure, I don't know a lot about this stuff.
The catch you added ( NoClassDefFoundError
) was ok, it is catching the classFor correctly. The problem has to do with some classes initialization. It is not the Screen class, that is kind of misleading I think.
I first tried logging that orchard code you were modifying with something like :
(try
(println "@@@@@ About to load " class (.getName (Thread/currentThread)))
(let [c (Class/forName (str class))]
(println "@@@@ loaded " c)
c)
(catch Exception _)
(catch NoClassDefFoundError _ (println "@@@@ NoClassDefFoundError"))
(catch LinkageError _))
But the results were even more confusing.
So I went ahead and created the smallest repo I found that reproduce the issue.
https://github.com/jpmonettas/cider-nrepl-bug-reprojust adding more info to the thread, I'm testing with the cider-nrepl-bug-repro project : • if you comment out (Class/forName ...) in orchard it works • but if instead you (try ... (catch Throwable)) then it doesn't work, which is weird that you can't catch that exception coming from the static initializer
ok, some progress here. What I figured out is if you initialize any javafx class without the toolkit initialized (which cider-nrepl is doing), then you will put the JavaFX system into a bad state :face_with_rolling_eyes:, and no matter if you try to initialize the toolkit after, it won't work anymore. You can reproduce this easily without cider-nrepl or anything, just with plain JavaFX
so on one side this is like a bug in JavaFX, but on the other side it is a bug on cider-nrepl warmup system that is assuming you can initialize any class, which will break systems that require stuff to be done before a class can be initialized
for now I patched the orchard.java/class-info*
try/catch with :
(try
(let [class-str (str class)]
(when-not (string/starts-with? class-str "javafx")
(Class/forName class-str)))
(catch Throwable _))
which solves the issue, but that is as hacky as it gets but on the other side it is a bug on cider-nrepl warmup system that is assuming you can initialize any class, which will break systems that require stuff to be done before a class can be initializedIf I (immediately) could, I'd just pass the false
second argument to Class/forName
(we already do in other places). But that happens to break defrecord/deftype analysis.
I think that the approach I'll take is:
• pass true
if the classname has a backing .clj file/resource that can be inferred and exists
• pass false
otherwise
◦ no class initialized, no issues for us or you
Thanks much for the observations - they sure have helped :)
I tried passing false to it already, but it fails further down, when something else touches that class, which ends up running the static initialization code
I reckon I could do what I outlined and then hunt for the second culprit And will make sure to turn your repro into a test case 👍
hmmm that is very weird, I tried passing false now and it works :thinking_face:
Class/forName needs a classloader, I'm running with this now (Class/forName class false @clojure.lang.Compiler/LOADER)
but not sure
dang, I was about to create a PR but I see that passing false there breaks a trillon tests
so I'm leaving the thread with that, let me know if you need me to try something else!
We normally use (.getContextClassLoader (Thread/currentThread))
Only two tests should break (amplified by the matrix) - related to deftype/defrecord
Detecting a .clj / .cljc resource
backing the class for deciding true/false is a fairly small task. But I'd be totally fine with tackling it myself
let me try that classloader change
here I'm leaving the PR, just for reference
it says like 122 failures
oh that is my bad, sorry
so many changes forgot that one
yeah, now only 2 are failing
ok, leaving this for now! will keep using the patched orchard version in the meantime
Ok! I'll do https://clojurians.slack.com/archives/C0617A8PQ/p1711372442495709?thread_ts=1711224784.839239&cid=C0617A8PQ then
OMG, now I'm trying again and the further down issue is back :rolling_on_the_floor_laughing:, I think it wasn't happening because I forgot that string there
Caused by: java.lang.ExceptionInInitializerError: Exception java.lang.IllegalStateException: Toolkit not initialized [in thread "clojure-agent-send-off-pool-0"]
at com.sun.javafx.application.PlatformImpl.runLater(PlatformImpl.java:436)
at com.sun.javafx.application.PlatformImpl.runLater(PlatformImpl.java:431)
at com.sun.javafx.application.PlatformImpl.setPlatformUserAgentStylesheet(PlatformImpl.java:724)
at com.sun.javafx.application.PlatformImpl.setDefaultPlatformUserAgentStylesheet(PlatformImpl.java:686)
at javafx.scene.control.Control.<clinit>(Control.java:98)
at java.base/java.lang.Class.forName0(Native Method)
at java.base/java.lang.Class.forName(Class.java:534)
at java.base/java.lang.Class.forName(Class.java:513)
at clojure.lang.RT.classForName(RT.java:2229)
at clojure.lang.RT.classForName(RT.java:2238)
at clojure.lang.Compiler.maybeResolveIn(Compiler.java:8130)
at clojure.core$ns_resolve.invokeStatic(core.clj:4386)
at clojure.core$ns_resolve.invokeStatic(core.clj:4375)
at clojure.core$resolve.invokeStatic(core.clj:4388)
at clojure.core$resolve.invoke(core.clj:4388)
at orchard.java.parser_utils$resolve.invokeStatic(parser_utils.clj:96)
at orchard.java.parser_utils$resolve.invoke(parser_utils.clj:91)
at orchard.java.parser_utils$source_path.invokeStatic(parser_utils.clj:108)
at orchard.java.parser_utils$source_path.invoke(parser_utils.clj:105)
at orchard.java.parser$source_info.invokeStatic(parser.clj:229)
at orchard.java.parser$source_info.invoke(parser.clj:220)
at clojure.lang.AFn.applyToHelper(AFn.java:154)
at clojure.lang.AFn.applyTo(AFn.java:144)
at clojure.lang.Var.applyTo(Var.java:707)
at clojure.core$apply.invokeStatic(core.clj:667)
at clojure.core$apply.invoke(core.clj:662)
at orchard.java$source_info_STAR_.invokeStatic(java.clj:124)
at orchard.java$source_info_STAR_.doInvoke(java.clj:101)
at clojure.lang.RestFn.invoke(RestFn.java:411)
at orchard.java$source_info.invokeStatic(java.clj:139)
at orchard.java$source_info.invoke(java.clj:135)
at orchard.java$class_info_STAR_.invokeStatic(java.clj:334)
at orchard.java$class_info_STAR_.invoke(java.clj:321)
at orchard.java$class_info.invokeStatic(java.clj:379)
at orchard.java$class_info.invoke(java.clj:371)
at cider.nrepl$warmup_orchard_caches_BANG_.invokeStatic(nrepl.clj:71)
at cider.nrepl$warmup_orchard_caches_BANG_.invoke(nrepl.clj:53)
at cider.nrepl$fn__6301.invokeStatic(nrepl.clj:77)
at cider.nrepl$fn__6301.invoke(nrepl.clj:76)
at clojure.core$binding_conveyor_fn$fn__5852.invoke(core.clj:2047)
at clojure.lang.AFn.call(AFn.java:18)
at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:317)
at java.base/java.util.concu
that is the new place
the parser_utils resolve
I'll check it in detail. I don't immediately know if we can or can't generically avoid this issue.
cider.nrepl$warmup_orchard_caches
uses false, always. So the class looks OK at that point.
Then I can't imagine how we'd use resolve
without evaluating stuff. Maybe it is possible not to use resolve.
If that wasn't possible, we'd have to blacklist the class and wait for https://github.com/clojure-emacs/orchard/issues/211 (very much necessary anyway)
yeah, that would be a way
also, this resolve https://github.com/clojure-emacs/orchard/blob/master/src-newer-jdks/orchard/java/parser_utils.clj#L91-L98
looks like it isn't going to be needed anymore?
anyway, won't bother you anymore, you probably have other stuff to do and this probably needs some hammock time
That would be neat :) If you are willing to further play with this LMK Indeed it's a busy week over here. I sense that it could all be pretty quick to solve, so if you're up to it, that could be fun as well Either way, thanks for the hints, it's almost as if you had omniscient debugging skills ;)
I don't think I know enough to make good decisions about how to fix this for real. I can hack it for sure, but you probably are going to make a much informed solution. Let me know if you need help debugging something or to try something on my env