Fork me on GitHub

I'm using the shadow-cljs node-repl, and getting lots of crashes using core.async. I'm finding the entire REPL (both with cider-jack-in-cljs and shadow-cljs server) crashes anytime I make an error inside of a go block. This is frustrating, because I have to restart the entire shadow-cljs server every time. Is anyone else experiencing this?


Here's an example of an error.


(defn <!
Error: <! used not in (go ...) block
    at Object.cljs$core$async$_LT__BANG_ [as _LT__BANG_] (/Users/neil/Desktop/loserCLI/.shadow-cljs/builds/node-repl/dev/out/cljs-runtime/cljs/core/async.cljs:92:1)
    at /Users/neil/Desktop/loserCLI/.shadow-cljs/builds/node-repl/dev/out/cljs-runtime/app/main.cljs:47:11
    at /Users/neil/Desktop/loserCLI/.shadow-cljs/builds/node-repl/dev/out/cljs-runtime/cljs/core.cljs:4736:15
    at /Users/neil/Desktop/loserCLI/.shadow-cljs/builds/node-repl/dev/out/cljs-runtime/cljs/core.cljs:4736:29
    at Object.sval (/Users/neil/Desktop/loserCLI/.shadow-cljs/builds/node-repl/dev/out/cljs-runtime/cljs/core.cljs:3438:7)
    at Object.cljs$core$ISeqable$_seq$arity$1 (/Users/neil/Desktop/loserCLI/.shadow-cljs/builds/node-repl/dev/out/cljs-runtime/cljs/core.cljs:3429:1)
    at Object.cljs$core$seq [as seq] (/Users/neil/Desktop/loserCLI/.shadow-cljs/builds/node-repl/dev/out/cljs-runtime/cljs/core.cljs:1234:7)
    at Function.cljs$core$IFn$_invoke$arity$1 (/Users/neil/Desktop/loserCLI/.shadow-cljs/builds/node-repl/dev/out/cljs-runtime/cljs/core.cljs:9953:1)
    at Function.cljs$core$IFn$_invoke$arity$1 (/Users/neil/Desktop/loserCLI/.shadow-cljs/builds/node-repl/dev/out/cljs-runtime/cljs/core.cljs:9966:1)
    at switch__30781__auto__ (/Users/neil/Desktop/loserCLI/.shadow-cljs/builds/node-repl/dev/out/cljs-runtime/app/main.cljs:45:3)


After this, if I simply try and evaluate (+ 2 2) at the REPL, I get another error (below), and I'm forced to shut down the entire server.


ERROR: Unhandled REPL handler exception processing message {:nrepl.middleware.print/buffer-size 4096, :ns app.main, :file *cider-repl Desktop/loserCLI:localhost:65433(clj)*, :nrepl.middleware.print/quota 1048576, :nrepl.middleware.print/print cider.nrepl.pprint/pprint, :op eval, :column 11, :line 35, :id 34, :code (+ 2 2), :nrepl.middleware.print/stream? 1, :nrepl.middleware.print/options {:right-margin 80}, :session 9e5bd5b2-32da-428c-b4ef-3ec6637ed31a}
java.lang.AssertionError: Assert failed: (some? worker)
	at shadow.cljs.devtools.server.repl_impl$do_repl.invokeStatic(repl_impl.clj:19)
	at shadow.cljs.devtools.server.repl_impl$do_repl.invoke(repl_impl.clj:19)
	at shadow.cljs.devtools.server.nrepl_impl$do_cljs_eval.invokeStatic(nrepl_impl.clj:143)
	at shadow.cljs.devtools.server.nrepl_impl$do_cljs_eval.invoke(nrepl_impl.clj:131)
	at shadow.cljs.devtools.server.nrepl_impl$handle.invokeStatic(nrepl_impl.clj:216)
	at shadow.cljs.devtools.server.nrepl_impl$handle.invoke(nrepl_impl.clj:210)
	at shadow.cljs.devtools.server.nrepl$middleware$fn__7184.invoke(nrepl.clj:40)
	at nrepl.middleware$wrap_conj_descriptor$fn__6114.invoke(middleware.clj:16)
	at cider.nrepl$wrap_out$fn__7479.invoke(nrepl.clj:312)
	at nrepl.middleware$wrap_conj_descriptor$fn__6114.invoke(middleware.clj:16)
	at cider.nrepl.middleware.inspect$eval_reply.invokeStatic(inspect.clj:64)
	at cider.nrepl.middleware.inspect$eval_reply.invoke(inspect.clj:62)
	at cider.nrepl.middleware.inspect$handle_inspect.invokeStatic(inspect.clj:95)
	at cider.nrepl.middleware.inspect$handle_inspect.invoke(inspect.clj:93)
	at clojure.lang.Var.invoke(
	at cider.nrepl$wrap_inspect$fn__7455.invoke(nrepl.clj:215)
	at nrepl.middleware$wrap_conj_descriptor$fn__6114.invoke(middleware.clj:16)
	at nrepl.middleware.caught$wrap_caught$fn__6589.invoke(caught.clj:97)
	at nrepl.middleware$wrap_conj_descriptor$fn__6114.invoke(middleware.clj:16)
	at nrepl.middleware.print$wrap_print$fn__6325.invoke(print.clj:234)
	at nrepl.middleware$wrap_conj_descriptor$fn__6114.invoke(middleware.clj:16)
	at cider.nrepl$wrap_slurp$fn__7387.invoke(nrepl.clj:110)
	at nrepl.middleware$wrap_conj_descriptor$fn__6114.invoke(middleware.clj:16)
	at cider.nrepl$wrap_undef$fn__7551.invoke(nrepl.clj:471)
	at nrepl.middleware$wrap_conj_descriptor$fn__6114.invoke(middleware.clj:16)
	at cider.nrepl.middleware.track_state$handle_tracker.invokeStatic(track_state.clj:240)
	at cider.nrepl.middleware.track_state$handle_tracker.invoke(track_state.clj:238)
	at clojure.lang.Var.invoke(
	at cider.nrepl$wrap_tracker$fn__7543.invoke(nrepl.clj:460)
	at nrepl.middleware$wrap_conj_descriptor$fn__6114.invoke(middleware.clj:16)
	at nrepl.middleware.session$session$fn__6931.invoke(session.clj:297)
	at nrepl.middleware$wrap_conj_descriptor$fn__6114.invoke(middleware.clj:16)
	at shadow.cljs.devtools.server.nrepl$start$fn__7215.invoke(nrepl.clj:138)
	at nrepl.server$handle_STAR_.invokeStatic(server.clj:19)
	at nrepl.server$handle_STAR_.invoke(server.clj:16)
	at nrepl.server$handle$fn__7009.invoke(server.clj:36)
	at clojure.core$binding_conveyor_fn$fn__5754.invoke(core.clj:2030)
	at java.util.concurrent.ThreadPoolExecutor.runWorker(
	at java.util.concurrent.ThreadPoolExecutor$


(By the way, the above <! is indeed in a go block in my code, so I'm not sure why the first error is even happening... but I can't really debug it if it shuts down my REPL every time.)


@neil.hansen.31 I can fix the second issue but the first is kinda a node problem. it just exits on uncaught exceptions and I cannot catch it in the REPL since its async.


Thanks @thheller, I'd be glad if this could be helpful. If the first issue can be solved by just catching the errors, I can be more careful. Is there a best practice for error handling in core.async + NodeJS +shadow-cljs?


I'm hesitant to install a handler by default here


> . It is not safe to resume normal operation after 'uncaughtException'.


Hmm, it does sound dangerous to use that directly. Thank you for the resource! I understand that the application probably needs to be restarted on an event like this. Is there a way to restart the NodeJS process that might be faster that entirely resetting shadow-cljs server?


you don't need to restart server.


I added a fix in master so the nrepl session is reset properly


Amazing, thanks. I'll try it out first thing in the morning.


@neil.hansen.31 also added automatic restart for node-repl if the node process crashes. state will be gone though. test 2.10.15


@thheller I can't believe you fixed this so quickly. It's already so much better.


I'm finding that the REPL works right away after my <! used not in (go...) block error. I get a message that says The previously used runtime disappeared. Will attempt to pick a new one when available but your state might be gone, followed by shadow-cljs - #11 ready!, which is great. Evaluation works right away. (+ 2 2) yields the expected result, and cider-eval-last-sexp is also working in the buffer.


However, once in the "new runtime" post-error, I'm getting errors when I try and evaluate def and defn expressions. I'm in a namespace called app.main, evaluating either kind of statement returns #object[ReferenceError ReferenceError: app is not defined]. This happens both with cider-eval-last-sexp in the buffer and with def and defn statements used in the REPL.


I just did a doom upgrade a moment to update all my Emacs packages, and I see that some REPL behaviour has changed. Now with the exact same steps (1. eval buffer 2. eval go block with <! problem), I'm no longer getting any error message at all in the REPL. No stack trace is printed; the only output is The previously used runtime disappeared. Will attempt to pick a new one when available but your state might be gone.


I have no idea what package update might have caused this, but let me know if you have any ideas of how to get the error message/stack trace back. I was confused on how to debug <! used not in (go...) block even when I could see the whole stack trace... Now I'm totally helpless 😛


^^^ and the messages are back after a few restarts. I don't know what's going on. #object[ReferenceError ReferenceError: app is not defined] is still problem.


@neil.hansen.31 like the message is telling you ... your state is gone. so the namespace you previously defined is gone with it.


You're absolutely right... I need to remember that it's being reset to a "empty" NodeJS environment. Thanks so much for your help. There's such a wild amount of complexity to wrap my head around in Clojure environments, I keep missing things that seem obvious.


I'm trying to write down all the little "conceptual" roadblocks that I run into. I'd love to send it your way at some point, hopefully to help make shadow-cljs more "self-documenting" to give clues to beginners like myself. I think having a good mental model of everything that's going on would help someone like me get more out of your User Guide.


I have upgraded my shadow-cljs dependency (and a few other dependencies. And now watch goes into endless compile loops. Strangely I also get "Warning: Nashorn engine is planned to be removed from a future JDK release". >Any ideas?


What happens is that the initial compile works; and when a change is detected that compile works also , but now it re-compiles this change over and over.