<< Back to previous view

[NREPL-46] nREPL crashes when required more than one time with :reload-all Created: 21/Dec/13  Updated: 02/May/15  Resolved: 12/Jan/15

Status: Closed
Project: tools.nrepl
Component/s: None
Affects Version/s: 0.2.2
Fix Version/s: None

Type: Defect Priority: Minor
Reporter: Alex Fowler Assignee: Chas Emerick
Resolution: Declined Votes: 1
Labels: bug

Irrelevant, but the provided test case project is for CounterClockWise on Eclipse. Although it should run just fine with vanilla lein.

Attachments: Zip Archive nrepl-test.zip    


When the namespace "clojure.tools.nrepl.server" is required more than once with :reload-all option, nREPL crashes. Accrding to current info it occures because some protocol instances get re-evaluated and are no longer the same JVM classes as they were before reload-all.

Steps to reproduce the bug in CCW:
1) Import the project into the workspace
2) Go into the core.clj
3) Click Clojure -> Load file in REPL
4) After the evaluation is complete, try evaluating (+ 1 2) in the repl. You should see no response at all.
5) Try writing something with letters, like "nrepl". The autocompletion will try and freeze and fail with the above exception.
6) Play around more to get a full hang or kill the REPL/Java to revive Eclipse.

Upon trying CCW autocompetion, the following exception occures, what might give some hint as to why:

Exception in thread "nREPL-worker-2" java.lang.IllegalArgumentException: No implementation of method: :send of protocol: #'clojure.tools.nrepl.transport/Transport found for class: clojure.tools.nrepl.middleware.pr_values$pr_values$fn$reify__1283
at clojure.core$_cache_protocol_fn.invoke(core_deftype.clj:541)
at clojure.tools.nrepl.transport$eval7291$fn_7292$G7280_7299.invoke(transport.clj:16)
at clojure.tools.nrepl.middleware.interruptible_eval$evaluate$fn_7726$fn_7739.invoke(interruptible_eval.clj:75)
at clojure.main$repl$fn__6597.invoke(main.clj:279)
at clojure.main$repl.doInvoke(main.clj:277)
at clojure.lang.RestFn.invoke(RestFn.java:1096)
at clojure.tools.nrepl.middleware.interruptible_eval$evaluate$fn__7726.invoke(interruptible_eval.clj:56)
at clojure.lang.AFn.applyToHelper(AFn.java:159)
at clojure.lang.AFn.applyTo(AFn.java:151)
at clojure.core$apply.invoke(core.clj:617)
at clojure.core$with_bindings_STAR_.doInvoke(core.clj:1788)
at clojure.lang.RestFn.invoke(RestFn.java:425)
at clojure.tools.nrepl.middleware.interruptible_eval$evaluate.invoke(interruptible_eval.clj:41)
at clojure.tools.nrepl.middleware.interruptible_eval$interruptible_eval$fn_1345$fn_1348.invoke(interruptible_eval.clj:171)
at clojure.core$comp$fn__4154.invoke(core.clj:2330)
at clojure.tools.nrepl.middleware.interruptible_eval$run_next$fn__7760.invoke(interruptible_eval.clj:138)
at clojure.lang.AFn.run(AFn.java:24)
at java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)
at java.lang.Thread.run(Unknown Source)

Comment by Chas Emerick [ 19/Aug/14 8:56 PM ]

Confirmed. Using lein repl (though you're right that the particulars of the tooling shouldn't matter):

user=> 3
user=> (require '[clojure.tools.nrepl.server] :reload-all)
user=> 2

user=> 1

Not sure if it's the protocol or the types that are implicated (or both), but resolving this is going to be unpleasant.

Comment by Chas Emerick [ 19/Aug/14 8:57 PM ]

Couple of questions:

  • Does the fact that this occurs matter to anyone in a meaningful way?
  • Would an acceptable solution be that reloading of the affected namespaces be no-ops?
Comment by Alex Fowler [ 25/Aug/14 9:34 AM ]

Well, in my case I have a project which is required to often reload various namespaces because they are updated in the background. If it happens that any of the namespaces refer to nrepl, the thing crashes.

The error happens due to implementation problems and is not "a correct error" from the POV of Clojure language so it is better to be fixed. However, of course, in the real world it could be rather hard to do so..

Chas, could you please explain more about the no-ops approach? Do you mean it is possible to somehow force loading nrepl just once?

Comment by Chas Emerick [ 25/Aug/14 10:20 AM ]

Yes, there are ways to prevent the re-definition of types and protocols, but I'd like to avoid doing so. It's a hack, and would be an impediment to developing nREPL itself.

Actually, you should be able to accomplish the same thing more easily in your project: rather than require nREPL namespaces in the ns form, use a top-level require form, wrapped in a suitable conditional to determine if nREPL has been loaded yet:

(when-not (resolve 'clojure.tools.nrepl/version)
  (require 'clojure.tools.nrepl))
Comment by Chas Emerick [ 12/Jan/15 8:43 AM ]

Not going to make any changes to nREPL in connection with this. :reload-all should be considered dangerous in general, IMO.

Comment by Terje Dahl [ 02/May/15 3:43 AM ]

This was very enlightening - both the fix for my mREPL-issue, as well as the warning of the danger of :reload-all. Thank you.

Generated at Tue May 03 02:02:57 CDT 2016 using JIRA 4.4#649-r158309.