Arne Brasseur
Arne Brasseur

Reputation: 1518

clojure.tools/namespace refresh fails with "No namespace: foo"

I'm using tools.namespace to provide smart reloading of namespaces on the REPL. However, when calling refresh or refresh-all, it throws an error.

user=> (require '[clojure.tools.namespace.repl :as tn])
user=> (tn/refresh)
:reloading (ep31.common ep31.routes ep31.config ep31.application user ep31.common-test ep31.example-test)
:error-while-loading user

java.lang.Exception: No namespace: ep31.config, compiling:(user.clj:1:1)

And it seems to end up in this weird state where (require ep31.config) works without an error, but afterwards the namespace isn't actually defined.

Upvotes: 5

Views: 1292

Answers (2)

Viesti
Viesti

Reputation: 77

I learned this the hard way, documentation for :target-path says (https://github.com/technomancy/leiningen/blob/master/sample.project.clj#L309-L313):

;; All generated files will be placed in :target-path. In order to avoid
;; cross-profile contamination (for instance, uberjar classes interfering
;; with development), it's recommended to include %s in in your custom
;; :target-path, which will splice in names of the currently active profiles.
:target-path "target/%s/"

I guess there has to be legacy reasons that :target-path "target/%s/" isn't the default.

Upvotes: 3

Arne Brasseur
Arne Brasseur

Reputation: 1518

I kind of figured this out, this seems to be a combination of circumstances

  • there were AOT compiled classes left in target/classes from doing lein uberjar previously
  • tools.namespace doesn't function correctly when loaded namespaces are AOT compiled
  • target/classes is by default on the classpath

So long story short, if you did a jar/uberjar build before, then remove target/ and things should start working again.

The question I haven't been able to solve yet is why target/classes is on the classpath to begin with. I'm suspecting it's being added by Leiningen, but haven't found yet where or why it's happening.

Upvotes: 12

Related Questions