Learning Clojure #8: Printing last stack trace in REPL
Occasionally you’ll hit an exception when calling into Java code and the REPL will tell you the message but not the stack trace:
user=> (java.util.Date. "foo") java.lang.IllegalArgumentException (NO_SOURCE_FILE:0)
The last exception is stored in *e by the REPL and you can use the Clojure stacktrace API to examine it more closely:
user=> (use 'clojure.stacktrace)
nil
user=> (print-stack-trace *e 5)
clojure.lang.Compiler$CompilerException: java.lang.IllegalArgumentException (NO_SOURCE_FILE:0)
at clojure.lang.Compiler.eval (Compiler.java:4658)
clojure.core/eval (core.clj:2035)
clojure.main$repl__7403$read_eval_print__7415.invoke (main.clj:183)
clojure.main$repl__7403.doInvoke (main.clj:200)
clojure.lang.RestFn.invoke (RestFn.java:426)
Here I dumped just the top 5 frames of the top-level exception. But I really want the cause of the exception not the wrapper exception created in the compiler. You can dump all the traces in the chain like this:
user=> (print-cause-trace *e 3)
clojure.lang.Compiler$CompilerException: java.lang.IllegalArgumentException (NO_SOURCE_FILE:0)
at clojure.lang.Compiler.eval (Compiler.java:4658)
clojure.core/eval (core.clj:2035)
clojure.main$repl__7403$read_eval_print__7415.invoke (main.clj:183)
Caused by: java.lang.IllegalArgumentException: null
at java.util.Date.parse (Date.java:598)
java.util.Date. (Date.java:255)
user/eval (NO_SOURCE_FILE:225)
Or print only the root cause like this:
user=> (print-stack-trace (root-cause *e) 3)
java.lang.IllegalArgumentException: null
at java.util.Date.parse (Date.java:598)
java.util.Date. (Date.java:255)
user/eval (NO_SOURCE_FILE:225)
Of course you can always just treat the *e as a Throwable and call normal Java methods on it too:
user=> (.printStackTrace *e)
java.lang.IllegalArgumentException (NO_SOURCE_FILE:0)
at clojure.lang.Compiler.eval(Compiler.java:4658)
at clojure.core$eval__5254.invoke(core.clj:2035)
at clojure.main$repl__7403$read_eval_print__7415.invoke(main.clj:183)
at clojure.main$repl__7403.doInvoke(main.clj:200)
at clojure.lang.RestFn.invoke(RestFn.java:426)
at clojure.main$repl_opt__7449.invoke(main.clj:254)
at clojure.main$main__7484.doInvoke(main.clj:341)
at clojure.lang.RestFn.invoke(RestFn.java:402)
at clojure.lang.Var.invoke(Var.java:355)
at clojure.lang.AFn.applyToHelper(AFn.java:171)
at clojure.lang.Var.applyTo(Var.java:476)
at clojure.main.main(main.java:37)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at jline.ConsoleRunner.main(ConsoleRunner.java:69)
Caused by: java.lang.IllegalArgumentException
at java.util.Date.parse(Date.java:598)
at java.util.Date.(Date.java:255)
at user$eval__362.invoke(NO_SOURCE_FILE:249)
at clojure.lang.Compiler.eval(Compiler.java:4642)
... 16 more
Happy hunting!

Hi! My name is Alex Miller and I live in St. Louis. I write Clojure for a living and currently work for
Hey Alex. Thanks for these little micro blogs on clojure, they’re pretty helpful.
I’m curious what you using as your repl or primary editor? I’ve really taken to emacs/slime setup, even though it’s my first real attempt at using emacs and that has been extra effort while learning clojure.
Hey Joe, I’m mostly using TextMate right now (and a separate repl). I’ve been trying to get emacs/slime/clojure set up but haven’t been terribly successful so far. I would definitely like to get into using that as my primary.
I’ve been struggling on my Ubuntu machine to get it all configured but on Windows Clojure Box is a blessing.