From 5f21ebd08d360d061c994e2b5f6b06c40233838a Mon Sep 17 00:00:00 2001 From: Andrey Antukh Date: Thu, 11 Jun 2026 16:59:00 +0200 Subject: [PATCH] :bug: Filter ignorable React removeChild errors at error boundary and fix HTML anti-pattern (#10145) * :bug: Filter ignorable exceptions in error-boundary onError callback The global uncaught-error-handler already skips NotFoundError/removeChild and other harmless errors, but react-error-boundary's onError callback fires independently of the window.onerror pipeline. This means the error boundary was still logging these errors and setting last-exception, causing them to continue appearing in error reports despite being non-actionable. Add the is-ignorable-exception? check to the error-boundary* onError so harmless errors are silently ignored, matching the behavior of the global handler. * :bug: Fix dangerouslySetInnerHTML anti-pattern in context-notification The previous code used dangerouslySetInnerHTML on the same element that could also contain React children. This is a React anti-pattern that can cause reconciliation mismatches and lead to removeChild DOMExceptions. Refactor to use two separate element branches: one for raw HTML injection and one for normal React children with links. --- frontend/src/app/main/ui/error_boundary.cljs | 14 ++++++++++- .../notifications/context_notification.cljs | 24 +++++++++---------- 2 files changed, 25 insertions(+), 13 deletions(-) diff --git a/frontend/src/app/main/ui/error_boundary.cljs b/frontend/src/app/main/ui/error_boundary.cljs index 60b42b45c0..226b87369b 100644 --- a/frontend/src/app/main/ui/error_boundary.cljs +++ b/frontend/src/app/main/ui/error_boundary.cljs @@ -37,8 +37,20 @@ ;; If the error is a stale-asset error (cross-build ;; module mismatch), force a hard page reload instead ;; of showing the error page to the user. - (if (errors/stale-asset-error? error) + (cond + (errors/stale-asset-error? error) (cf/throttled-reload :reason (ex-message error)) + + ;; If the error is known to be harmless (browser + ;; extensions, React DOM conflicts, etc.), ignore it + ;; silently — the global uncaught-error-handler + ;; already does this, but react-error-boundary's + ;; onError fires independently of the window.onerror + ;; pipeline, so we must also filter here. + (errors/is-ignorable-exception? error) + nil + + :else (do (set! errors/last-exception error) (ex/print-throwable error) diff --git a/frontend/src/app/main/ui/notifications/context_notification.cljs b/frontend/src/app/main/ui/notifications/context_notification.cljs index 6777dddf64..99259ddb99 100644 --- a/frontend/src/app/main/ui/notifications/context_notification.cljs +++ b/frontend/src/app/main/ui/notifications/context_notification.cljs @@ -54,16 +54,16 @@ ;; The content can arrive in markdown format, in these cases ;; we will use the prop is-html to true to indicate it and ;; that the html injection is performed and the necessary css classes are applied. - [:div {:class (stl/css :context-text) - :dangerouslySetInnerHTML (when is-html #js {:__html content})} - (when-not is-html - [:* - content - (when (some? links) - (for [[index link] (d/enumerate links)] - ;; TODO Review this component - [:& lb/link-button {:class (stl/css :link) - :on-click (:callback link) - :value (:label link) - :key (dm/str "link-" index)}]))])]]) + (if is-html + [:div {:class (stl/css :context-text) + :dangerouslySetInnerHTML #js {:__html content}}] + [:div {:class (stl/css :context-text)} + content + (when (some? links) + (for [[index link] (d/enumerate links)] + ;; TODO Review this component + [:& lb/link-button {:class (stl/css :link) + :on-click (:callback link) + :value (:label link) + :key (dm/str "link-" index)}]))])])