portal

azimpel 2025-07-13T11:13:55.983899Z

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?

djblue 2025-07-14T17:23:51.682439Z

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.

djblue 2025-07-14T17:59:28.042519Z

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.

azimpel 2025-07-14T19:35:53.191259Z

@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.

azimpel 2025-07-14T19:40:35.374399Z

@djblue Chris, the issue is fixed 👍 Thank you very much! What was the actual problem in two words? Unhandled error propagation?

Steven Lombardi 2025-07-14T19:46:47.794089Z

Seems like whatever you're tapping is reading stale state. Are you tapping the pedestal context?

djblue 2025-07-14T19:46:53.556499Z

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.

Steven Lombardi 2025-07-14T19:48:56.389929Z

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.

Steven Lombardi 2025-07-14T19:50:39.417579Z

If somehow you're ending up toStringing a web socket frame after it's been cleaned up that would certainly cause this

azimpel 2025-07-14T19:55:57.257479Z

@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:

azimpel 2025-07-14T19:59:17.013059Z

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.

Steven Lombardi 2025-07-15T05:21:49.866749Z

Strange. Thanks for the info.

azimpel 2025-07-13T11:14:40.618199Z

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.

lukasz 2025-07-13T15:43:52.427379Z

are you trying to tap> something that contains Jetty server instance? Looks like underlying serialization machinery powering Portal is choking on that

azimpel 2025-07-13T21:16:36.650139Z

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.

Steven Lombardi 2025-07-13T22:52:05.436979Z

If you configure tap> to just output to a basic console or your repl, does the problem remain?