Fork me on GitHub

At work we just ran into a situation where Clojure was trying to report-error, which calls pprint on the exception, and the ex-data in the exception is not printable so printing code blew up so you lose the exception information completely. Would there be interest in making report-error more robust so you still get useful output from it, or would this be considered too much of an edge case?


non printable ex-data is weird to me, as I rarely use ex-data for anything other than printing (so I know more about the exception context in the printed output)


Specifically, this is a case where ex-data is essentially a lazy sequence and realizing it throws an exception (it’s a bit more complex than that but…).


Hmm, in trying to boil this down to a simpler repro case, I can’t actually get a version that loses exception data like we’re seeing at work.


Example of what I’m talking about:

(! 536)-> cat blowup.clj 
(def bad (delay (/ 1 0)))

(def wrap (lazy-seq (cons @bad [])))

(throw (ex-info "boom" {:explode wrap}))
(! 537)-> clojure -M blowup.clj 
Exception in thread "main" java.lang.ArithmeticException: Divide by zero
	at clojure.lang.Numbers.divide(
	at clojure.lang.Numbers.divide(
	at user$fn__136.invokeStatic(blowup.clj:1)
	at user$fn__136.invoke(blowup.clj:1)
	at clojure.lang.Delay.deref(
	at clojure.core$deref.invokeStatic(core.clj:2324)
	at clojure.core$deref.invoke(core.clj:2310)
	at user$fn__138.invokeStatic(blowup.clj:3)
	at user$fn__138.invoke(blowup.clj:3)
	at clojure.lang.LazySeq.sval(
	at clojure.pprint$pprint.invoke(pprint_base.clj:241)
	at clojure.lang.Var.invoke(
	at clojure.main$report_error$fn__9184$fn__9185.invoke(main.clj:603)
	at clojure.main$report_error$fn__9184.invoke(main.clj:602)
	at clojure.main$report_error.invokeStatic(main.clj:601)
	at clojure.main$main.invokeStatic(main.clj:666)
	at clojure.main$main.doInvoke(main.clj:616)
	at clojure.lang.RestFn.applyTo(
	at clojure.lang.Var.applyTo(
	at clojure.main.main(
Instead of getting a single line error and an EDN file. You get the underlying exception but you don’t get any info about the ex-info that was actually thrown.