bhb / expound

Human-optimized error messages for clojure.spec
Eclipse Public License 1.0
927 stars 24 forks source link

"Cannot convert path" on instrumentation failures in the wild #194

Closed jeaye closed 4 years ago

jeaye commented 4 years ago

Hey Ben!

I've been looking into an issue I've seen with the Expound + Orchestra marriage in the wild. The reproduction case is very simple, but I haven't been able to reproduce it in Orchestra's tests (in fact, I have an Expound test case and it works swimmingly).

So, the code is actually taken from my Expound test case (linked above), but run within the environment of a larger production system. Basically, it boils down to this:

; Some spec'd function.
(defn-spec expound' true?
  [blah string?]
  true)

; Some invalid call to that function.
(expound' 42)

Of course, Orchestra throws an exception with the explain data. Here's what it looks like:

clojure.lang.ExceptionInfo: Call to #'foo.bar/expound' did not conform to spec.
{:clojure.spec.alpha/problems [{:path [:blah]
                                :pred clojure.core/string?
                                :val 42
                                :via []
                                :in [0]}]
 :clojure.spec.alpha/spec #object[clojure.spec.alpha$regex_spec_impl$reify__2499 0x3dd8b6b "clojure.spec.alpha$regex_spec_impl$reify__2499@3dd8b6b"]
 :clojure.spec.alpha/value (42)
 :clojure.spec.alpha/fn foo.bar/expound'
 :clojure.spec.alpha/args (42)
 :clojure.spec.alpha/failure :instrument
 :orchestra.spec.test/caller {:file "core.clj"
                              :line 70
                              :var-scope foo.bar/fn--172911}}

However, if I take that exception and do a little something like this:

(expound/printer (ex-data e))

; Or something like this (with an alter-var-root!):
(s/explain-out (ex-data e))

Then Expound gets upset and says this:

#error {:cause "Cannot convert path. This can be caused by using conformers to transform values, which is not supported in Expound"
        :data {:form com.okletsplay.back-end.shared.endpoint/expound'
               :val 42
               :in [0]
               :in' []}
        :via
        [{:type clojure.lang.ExceptionInfo
          :message "Cannot convert path. This can be caused by using conformers to transform values, which is not supported in Expound"
          :data {:form foo.bar/expound'
                 :val 42
                 :in [0]
                 :in' []}
          :at [expound.paths$in_with_kps invokeStatic "paths.cljc" 183]}]
        :trace
        [[expound.paths$in_with_kps invokeStatic "paths.cljc" 183]
         [expound.paths$in_with_kps invoke "paths.cljc" 180]
         [expound.problems$adjust_in invokeStatic "problems.cljc" 86]
         [expound.problems$adjust_in invoke "problems.cljc" 81]
         [clojure.core$partial$fn__5839 invoke "core.clj" 2624]
         [clojure.core$comp$fn__5807 invoke "core.clj" 2569]
         [clojure.core$comp$fn__5807 invoke "core.clj" 2569]
         [clojure.core$comp$fn__5807 invoke "core.clj" 2569]
         [clojure.core$comp$fn__5807 invoke "core.clj" 2569]
         [clojure.core$comp$fn__5807 invoke "core.clj" 2569]
         [clojure.core$map$fn__5866 invoke "core.clj" 2753]
         [clojure.lang.LazySeq sval "LazySeq.java" 42]
         [clojure.lang.LazySeq seq "LazySeq.java" 51]
         [clojure.lang.RT seq "RT.java" 535]
         [clojure.core$seq__5402 invokeStatic "core.clj" 137]
         [clojure.core.protocols$seq_reduce invokeStatic "protocols.clj" 24]
         [clojure.core.protocols$fn__8146 invokeStatic "protocols.clj" 75]
         [clojure.core.protocols$fn__8146 invoke "protocols.clj" 75]
         [clojure.core.protocols$fn__8088$G__8083__8101 invoke "protocols.clj" 13]
         [clojure.core$reduce invokeStatic "core.clj" 6828]
         [clojure.core$group_by invokeStatic "core.clj" 7146]
         [clojure.core$group_by invoke "core.clj" 7146]
         [expound.alpha$groups invokeStatic "alpha.cljc" 477]
         [expound.alpha$groups invoke "alpha.cljc" 475]
         [expound.alpha$print_explain_data invokeStatic "alpha.cljc" 693]
         [expound.alpha$print_explain_data invoke "alpha.cljc" 687]
         [expound.alpha$printer_str invokeStatic "alpha.cljc" 842]
         [expound.alpha$printer_str invoke "alpha.cljc" 824]
         [expound.alpha$custom_printer$fn__1221 invoke "alpha.cljc" 882]
         [clojure.spec.alpha$explain_out invokeStatic "alpha.clj" 259]
         [clojure.spec.alpha$explain_out invoke "alpha.clj" 255]
         [foo.bar$fn__172911 invokeStatic "core.clj" 70]]}

I'm not sure yet if this is an issue with Expound or if Orchestra should be changed to give it different data. I also don't know why it's not happening in my test case, but it's happening in the wild. I'm hoping you have some info on this and I'd be happy to make any necessary changes to Orchestra to make sure it can work well with Expound. Just let me know what you need!

Thank you, sir.

P.S. The best Orchestra version to use right now is development-SNAPSHOT, which has been completely rewritten to be much simpler. Rather than entirely forking spec, it just patches a single function to instrument everything.

bhb commented 4 years ago

@jeaye Thanks for reporting this! 😄

I could be mistaken, but that error message looks to be from an older version of Expound. Is it possible that the case in the wild is using a version prior to 0.7.2? It looks like your test is using the latest Expound (0.8.5), which is why you may be seeing different behavior here.

The reason I ask is that this sounds like it might be an instance of this bug.

jeaye commented 4 years ago

Nooooooo. I think you're right. I'll check in a couple of hours and get back to you. :facepalm:

jeaye commented 4 years ago

Yeah, that is the case. That project was using 0.7.1. :facepalm: Thanks for taking the time to look into it!

bhb commented 4 years ago

No worries, glad that fixed it!