Hi guys, I'm assuming it's not a portal specific issue, but maybe somebody already faced it. I started to use portal in a new project which has latest io.pedestal/pedestal.jetty (v0.8.0-beta-1) as a direct dependency.
As soon as jetty is started it begin to interfere with httpkit used by portal (I suppose). Maybe there's even more interference by other libs, especially this line from the stacktrace makes me suspicious: cider.nrepl.print_method$replace_with_orchard_print$fn__3607.invoke(print_method.clj:29)
Without knowing exactly how portal operates, I'v a gut feeling it has something with (delayed?) printing of Clojure data structures which somehow gets intercepted (unexpectedly?) by cider. Any ideas?
Haven't released it yet, but I think https://github.com/djblue/portal/commit/2fa52bbf882a560bd193645670f026072898383e should at least prevent Portal from breaking when pr-str throws. You can try it locally by loading the updated version of portal.runtime in the commit.
Just released https://github.com/djblue/portal/releases/tag/0.59.2 with the fix after some more testing. Let me know if this doesn't fix the issue.
@lambeauxworks looks like it does, only a small part of the request map gets printed (probably values gets printed incrementally) the rest is just swallowed.
@djblue Chris, the issue is fixed 👍 Thank you very much! What was the actual problem in two words? Unhandled error propagation?
Seems like whatever you're tapping is reading stale state. Are you tapping the pedestal context?
I think so. Portal uses pr-str to serialize values it is unfamiliar with. In this instance, calling pr-str on a value was causing an exception. I typically expect pr-str to never throw exceptions, but it looks like something in jetty is throwing when converting an object to a string. Users will now see #object [<Type> unprintable] when such print exceptions get thrown for a given object instead.
Yeah the root cause here isn't portal, although as Chris said, it's good for portal to be resilient when these kinds of weird cases happen. But I'm really curious what you're actually tapping and how you're doing it.
If somehow you're ending up toStringing a web socket frame after it's been cleaned up that would certainly cause this
@lambeauxworks well, it's "just" (tm) the enriched request map, at least I was not expecting it to contain something unprintable. Seems that the new jetty response behaves unexpectedly (afaik had no issues with older jetty in pedestal 0.7) Here's the tapped value:
I'm registering portal's handler in my dev namespace regularly: (add-tap #'p/submit)
And afterwards tapping the incoming request from a request handler fn:
(fn [req]
(tap> req)
,, some more code
(create-response req))
Nothing special here.Strange. Thanks for the info.
Sun Jul 13 12:42:07 CEST 2025 [worker-1] ERROR - handle websocket frame org.httpkit.server.Frame$TextFrame@59cc35cf
java.lang.IllegalStateException: Response does not exist (likely recycled)
at org.eclipse.jetty.ee10.servlet.ServletChannel.getResponse(ServletChannel.java:301)
at org.eclipse.jetty.ee10.servlet.ServletApiResponse.getResponse(ServletApiResponse.java:97)
at org.eclipse.jetty.ee10.servlet.ServletApiResponse.toString(ServletApiResponse.java:527)
at clojure.core$str.invokeStatic(core.clj:555)
at clojure.core$print_object.invokeStatic(core_print.clj:117)
at clojure.core$fn__7382.invokeStatic(core_print.clj:120)
at clojure.core$fn__7382.invoke(core_print.clj:120)
at clojure.lang.MultiFn.invoke(MultiFn.java:234)
at orchard.print$eval3596$fn__3597.invoke(print.clj:222)
at clojure.lang.MultiFn.invoke(MultiFn.java:234)
at orchard.print$print_coll_item.invokeStatic(print.clj:58)
at orchard.print$print_coll_item.invoke(print.clj:51)
at orchard.print$print_coll.invokeStatic(print.clj:81)
at orchard.print$print_coll.invoke(print.clj:61)
at orchard.print$print_map.invokeStatic(print.clj:137)
at orchard.print$print_map.invoke(print.clj:131)
at orchard.print$eval3542$fn__3543.invoke(print.clj:140)
at clojure.lang.MultiFn.invoke(MultiFn.java:234)
at orchard.print$print_coll_item.invokeStatic(print.clj:59)
at orchard.print$print_coll_item.invoke(print.clj:51)
at orchard.print$print_coll.invokeStatic(print.clj:75)
at orchard.print$print_coll.invoke(print.clj:61)
at orchard.print$print_coll.invokeStatic(print.clj:63)
at orchard.print$print_coll.invoke(print.clj:61)
at orchard.print$eval3533$fn__3534.invoke(print.clj:126)
at clojure.lang.MultiFn.invoke(MultiFn.java:234)
at orchard.print$print_coll_item.invokeStatic(print.clj:59)
at orchard.print$print_coll_item.invoke(print.clj:51)
at orchard.print$print_coll.invokeStatic(print.clj:75)
at orchard.print$print_coll.invoke(print.clj:61)
at orchard.print$print_coll.invokeStatic(print.clj:63)
at orchard.print$print_coll.invoke(print.clj:61)
at orchard.print$eval3529$fn__3530.invoke(print.clj:123)
at clojure.lang.MultiFn.invoke(MultiFn.java:234)
at orchard.print$eval3555$fn__3556.invoke(print.clj:171)
at clojure.lang.MultiFn.invoke(MultiFn.java:234)
at cider.nrepl.print_method$replace_with_orchard_print$fn__3607.invoke(print_method.clj:29)
at clojure.lang.MultiFn.invoke(MultiFn.java:234)
at clojure.core$pr_on.invokeStatic(core.clj:3700)
at clojure.core$pr_on.invoke(core.clj:3694)
at clojure.core$print_sequential.invokeStatic(core_print.clj:66)
at clojure.core$fn__7414.invokeStatic(core_print.clj:174)
at clojure.core$fn__7414.invoke(core_print.clj:174)
at clojure.lang.MultiFn.invoke(MultiFn.java:234)
at clojure.core$pr_on.invokeStatic(core.clj:3700)
at clojure.core$pr_on.invoke(core.clj:3694)
at clojure.core$print_prefix_map$fn__7437.invoke(core_print.clj:233)
at clojure.core$print_sequential.invokeStatic(core_print.clj:66)
at clojure.core$print_prefix_map.invokeStatic(core_print.clj:229)
at clojure.core$print_map.invokeStatic(core_print.clj:238)
at clojure.core$fn__7466.invokeStatic(core_print.clj:266)
at clojure.core$fn__7466.invoke(core_print.clj:263)
at clojure.lang.MultiFn.invoke(MultiFn.java:234)
at clojure.core$print_throwable$print_via__7570.invoke(core_print.clj:518)
at clojure.core$print_throwable.invokeStatic(core_print.clj:530)
at clojure.core$fn__7589.invokeStatic(core_print.clj:545)
at clojure.core$fn__7589.invoke(core_print.clj:545)
at clojure.lang.MultiFn.invoke(MultiFn.java:234)
at clojure.core$pr_on.invokeStatic(core.clj:3700)
at clojure.core$pr.invokeStatic(core.clj:3703)
at clojure.core$pr.invoke(core.clj:3703)
at clojure.lang.AFn.applyToHelper(AFn.java:154)
at clojure.lang.RestFn.applyTo(RestFn.java:135)
at clojure.core$apply.invokeStatic(core.clj:667)
at clojure.core$pr_str.invokeStatic(core.clj:4785)
at clojure.core$pr_str.doInvoke(core.clj:4785)
at clojure.lang.RestFn.invoke(RestFn.java:411)
at portal.runtime$pr_str_SINGLEQUOTE_.invokeStatic(runtime.cljc:210)
at portal.runtime$pr_str_SINGLEQUOTE_.invoke(runtime.cljc:208)
at portal.runtime$to_object.invokeStatic(runtime.cljc:228)
at portal.runtime$to_object.invoke(runtime.cljc:213)
at portal.runtime$eval17249$fn__17250.invoke(runtime.cljc:270)
at portal.runtime.cson$eval16817$fn__16818$G__16808__16825.invoke(cson.cljc:25)
at portal.runtime.cson$to_json.invokeStatic(cson.cljc:36)
at portal.runtime.cson$to_json.invoke(cson.cljc:36)
at portal.runtime.cson$tagged_map$fn__17042.invoke(cson.cljc:683)
at clojure.lang.PersistentArrayMap.kvreduce(PersistentArrayMap.java:475)
at clojure.core$fn__8555.invokeStatic(core.clj:6987)
at clojure.core$fn__8555.invoke(core.clj:6967)
at clojure.core.protocols$fn__8283$G__8278__8292.invoke(protocols.clj:174)
at clojure.core$reduce_kv.invokeStatic(core.clj:6998)
at clojure.core$reduce_kv.invoke(core.clj:6989)
at portal.runtime.cson$tagged_map.invokeStatic(cson.cljc:679)
at portal.runtime.cson$tagged_map.invoke(cson.cljc:673)
at portal.runtime.cson$tagged_map.invokeStatic(cson.cljc:677)
at portal.runtime.cson$tagged_map.invoke(cson.cljc:673)
at portal.runtime.cson$tagged_map.invokeStatic(cson.cljc:675)
at portal.runtime.cson$tagged_map.invoke(cson.cljc:673)
at portal.runtime.cson$eval17057$fn__17058.invoke(cson.cljc:720)
at portal.runtime.cson$eval16817$fn__16818$G__16808__16825.invoke(cson.cljc:25)
at portal.runtime.cson$to_json.invokeStatic(cson.cljc:36)
at portal.runtime.cson$to_json.invoke(cson.cljc:36)
at portal.runtime.cson$push_meta.invokeStatic(cson.cljc:208)
at portal.runtime.cson$push_meta.invoke(cson.cljc:206)
at portal.runtime.cson$tagged_map.invokeStatic(cson.cljc:685)
at portal.runtime.cson$tagged_map.invoke(cson.cljc:673)
at portal.runtime.cson$tagged_map.invokeStatic(cson.cljc:677)
at portal.runtime.cson$tagged_map.invoke(cson.cljc:673)
at portal.runtime.cson$tagged_map.invokeStatic(cson.cljc:675)
at portal.runtime.cson$tagged_map.invoke(cson.cljc:673)
at portal.runtime.cson$eval17057$fn__17058.invoke(cson.cljc:720)
at portal.runtime.cson$eval16817$fn__16818$G__16808__16825.invoke(cson.cljc:25)
at portal.runtime.cson$to_json.invokeStatic(cson.cljc:36)
at portal.runtime.cson$to_json.invoke(cson.cljc:36)
at portal.runtime.cson$tagged_map$fn__17042.invoke(cson.cljc:683)
at clojure.lang.PersistentArrayMap.kvreduce(PersistentArrayMap.java:475)
at clojure.core$fn__8555.invokeStatic(core.clj:6987)
at clojure.core$fn__8555.invoke(core.clj:6967)
at clojure.core.protocols$fn__8283$G__8278__8292.invoke(protocols.clj:174)
at clojure.core$reduce_kv.invokeStatic(core.clj:6998)
at clojure.core$reduce_kv.invoke(core.clj:6989)
at portal.runtime.cson$tagged_map.invokeStatic(cson.cljc:679)
at portal.runtime.cson$tagged_map.invoke(cson.cljc:673)
at portal.runtime.cson$tagged_map.invokeStatic(cson.cljc:677)
at portal.runtime.cson$tagged_map.invoke(cson.cljc:673)
at portal.runtime.cson$tagged_map.invokeStatic(cson.cljc:675)
at portal.runtime.cson$tagged_map.invoke(cson.cljc:673)
at portal.runtime.cson$eval17057$fn__17058.invoke(cson.cljc:720)
at portal.runtime.cson$eval16817$fn__16818$G__16808__16825.invoke(cson.cljc:25)
at portal.runtime.cson$to_json.invokeStatic(cson.cljc:36)
at portal.runtime.cson$to_json.invoke(cson.cljc:36)
at portal.runtime.json_buffer$with_buffer.invokeStatic(json_buffer.cljc:156)
at portal.runtime.json_buffer$with_buffer.invoke(json_buffer.cljc:147)
at portal.runtime.cson$write.invokeStatic(cson.cljc:810)
at portal.runtime.cson$write.invoke(cson.cljc:806)
at portal.runtime$write.invokeStatic(runtime.cljc:310)
at portal.runtime$write.invoke(runtime.cljc:308)
at portal.runtime.rpc$on_open$fn__18690.invoke(rpc.cljc:11)
at portal.runtime.rpc$on_receive$on_done__18698.invoke(rpc.cljc:34)
at portal.runtime$invoke.invokeStatic(runtime.cljc:458)
at portal.runtime$invoke.invoke(runtime.cljc:451)
at clojure.lang.Var.invoke(Var.java:390)
at portal.runtime.rpc$on_receive.invokeStatic(rpc.cljc:39)
at portal.runtime.rpc$on_receive.invoke(rpc.cljc:28)
at portal.runtime.jvm.server$eval18715$fn__18716$fn__18717.invoke(server.clj:44)
at clojure.core$partial$fn__5927.are you trying to tap> something that contains Jetty server instance? Looks like underlying serialization machinery powering Portal is choking on that
Hi, I'm taping just a regular http request map. Normally it shouldn't be an issue and I'm pretty sure it worked in my previous setup. I was just hoping that it does ring a bell for somebody before digging into that interleaved printing issue. And afaik printing is a bit involved.
If you configure tap> to just output to a basic console or your repl, does the problem remain?