From 80d165ed5b5efe80d993992432f3f51cd8f493bf Mon Sep 17 00:00:00 2001 From: Andrey Antukh Date: Wed, 11 Mar 2026 12:08:11 +0000 Subject: [PATCH] :bug: Fix unhandled AbortError in HTTP fetch requests Identify and silence "signal is aborted without reason" errors by: - Providing an explicit reason to AbortController when subscriptions are disposed. - Updating the global error handler to ignore AbortError exceptions. - Ensuring unhandled rejections use the ignorable exception filter. The root cause was RxJS disposal calling .abort() without a reason, combined with the on-unhandled-rejection handler missing the ignorable error filter. Signed-off-by: Andrey Antukh --- frontend/src/app/main/errors.cljs | 7 ++++++- frontend/src/app/util/http.cljs | 7 ++++++- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/frontend/src/app/main/errors.cljs b/frontend/src/app/main/errors.cljs index 205452e8d8..fe5a82518e 100644 --- a/frontend/src/app/main/errors.cljs +++ b/frontend/src/app/main/errors.cljs @@ -343,7 +343,12 @@ (= message "Possible side-effect in debug-evaluate") (= message "Unexpected end of input") (str/starts-with? message "invalid props on component") - (str/starts-with? message "Unexpected token ")))) + (str/starts-with? message "Unexpected token ") + ;; Abort errors are expected when an in-flight HTTP request is + ;; cancelled (e.g. via RxJS unsubscription / take-until). They + ;; are handled gracefully inside app.util.http/fetch and must + ;; NOT be surfaced as application errors. + (= (.-name ^js cause) "AbortError")))) (on-unhandled-error [event] (.preventDefault ^js event) diff --git a/frontend/src/app/util/http.cljs b/frontend/src/app/util/http.cljs index 0fd9be60b7..a25f030d3f 100644 --- a/frontend/src/app/util/http.cljs +++ b/frontend/src/app/util/http.cljs @@ -123,10 +123,15 @@ (/ current-time (inc count))) count (inc count)] (swap! network-averages assoc (:path uri) {:count count :average average}))))) + (fn [] (vreset! unsubscribed? true) (when @abortable? - (.abort ^js controller))))))) + ;; Provide an explicit reason so that the resulting AbortError carries + ;; a meaningful message instead of the browser default + ;; "signal is aborted without reason". + (.abort ^js controller (ex-info (str "fetch to '" uri "' is aborted") + {:uri uri})))))))) (defn response->map [response]