Skip to content

fix(voting): prevent Google Translate insertBefore crash#418

Merged
yhabib merged 2 commits into
mainfrom
fix/google-translate-insertbefore-crash
Jul 13, 2026
Merged

fix(voting): prevent Google Translate insertBefore crash#418
yhabib merged 2 commits into
mainfrom
fix/google-translate-insertbefore-crash

Conversation

@yhabib

@yhabib yhabib commented Jul 13, 2026

Copy link
Copy Markdown
Collaborator

Motivation

A user reported that voting crashes the app: the vote goes through, then the whole route dies with "Something went wrong" and Failed to execute 'insertBefore' on 'Node': The node before which the new node is to be inserted is not a child of this node. It only reproduces when the page is being auto-translated. In-browser translators like Google Translate rewrite text nodes by wrapping them in their own <font> elements, so React's stored node references no longer match the real DOM and the next reconcile throws during commit.

Changes

  • Added domTranslationGuard that hardens Node.prototype.insertBefore/removeChild to append or no-op when the reference/child node was re-parented by a translator, instead of throwing.
  • Installed the guard once in main.tsx before React mounts.
  • Added unit tests reproducing the re-parented-node case for both methods.

Copilot AI review requested due to automatic review settings July 13, 2026 08:55
@yhabib yhabib requested a review from a team as a code owner July 13, 2026 08:55
@zeropath-ai

zeropath-ai Bot commented Jul 13, 2026

Copy link
Copy Markdown

No security or compliance issues detected. Reviewed everything up to 11d4bba.

Security Overview
Detected Code Changes
Change Type Relevant files
Enhancement ► src/governance-app-frontend/src/common/utils/domTranslationGuard.ts
       Implement DOM translation guard to stabilize inserts/removals by handling translator-wrapped nodes
Enhancement ► src/governance-app-frontend/src/common/utils/domTranslationGuard.spec.ts
       Add tests for domTranslationGuard behavior
Enhancement ► src/governance-app-frontend/src/main.tsx
       Install domTranslationGuard before app mount

@github-actions

github-actions Bot commented Jul 13, 2026

Copy link
Copy Markdown

📊 Build Bundle Stats

The latest build generated the following assets:

dist/index.html                                           2.39 kB │ gzip:   0.84 kB
dist/assets/index-ZZaLvKLe.css                          131.38 kB │ gzip:  21.38 kB
dist/assets/externalServices-CK4eoRia.js                  0.19 kB │ gzip:   0.16 kB
dist/assets/address-C-4H442a.js                           0.20 kB │ gzip:   0.15 kB
dist/assets/Skeleton-Bgoxabxt.js                          0.46 kB │ gzip:   0.34 kB
dist/assets/useTvlValue-Btrexp6M.js                       0.57 kB │ gzip:   0.39 kB
dist/assets/numbers-B9oiH86s.js                           0.58 kB │ gzip:   0.36 kB
dist/assets/service-DxqNxKjV.js                           0.59 kB │ gzip:   0.38 kB
dist/assets/Spinner-CZi6lS8l.js                           0.59 kB │ gzip:   0.41 kB
dist/assets/PageHeader-Czh9Jiub.js                        0.77 kB │ gzip:   0.45 kB
dist/assets/CertifiedBadge-C-pdx5aQ.js                    0.81 kB │ gzip:   0.48 kB
dist/assets/Separator-dFULeHAY.js                         0.83 kB │ gzip:   0.49 kB
dist/assets/useIcpIndex-BMwPyLlv.js                       1.07 kB │ gzip:   0.63 kB
dist/assets/rolldown-runtime-CMxvf4Kt.js                  1.21 kB │ gzip:   0.67 kB
dist/assets/addressBook-_uX5bf_n.js                       1.66 kB │ gzip:   0.99 kB
dist/assets/useCommandPaletteSettings-Bpv5rVbB.js         1.73 kB │ gzip:   0.86 kB
dist/assets/useGovernanceAppCanister-CoqvN6mv.js          1.91 kB │ gzip:   0.96 kB
dist/assets/AnimatedNumber-DEESajkh.js                    1.96 kB │ gzip:   1.12 kB
dist/assets/useIcpIndexTransactionsPolling-CwW8l2s-.js    2.03 kB │ gzip:   1.09 kB
dist/assets/EmptyActionState-CQGpSIEp.js                  2.52 kB │ gzip:   1.12 kB
dist/assets/ToggleGroup-x6fCHMXt.js                       3.09 kB │ gzip:   1.40 kB
dist/assets/tickers-B3hd-_mC.js                           3.10 kB │ gzip:   1.48 kB
dist/assets/Switch-DrR8z4ce.js                            3.22 kB │ gzip:   1.44 kB
dist/assets/SensitiveValue-Dt8kAIO9.js                    7.33 kB │ gzip:   3.28 kB
dist/assets/routes-CZDWQ25w.js                            7.46 kB │ gzip:   2.46 kB
dist/assets/badge-Dh2u1ab_.js                             8.12 kB │ gzip:   2.36 kB
dist/assets/spamFilter-Epatj7fv.js                        8.54 kB │ gzip:   3.80 kB
dist/assets/TopicFollowingAccordion-MbpMdSfM.js           9.34 kB │ gzip:   3.81 kB
dist/assets/MutationDialog-CfxpKMc0.js                    9.53 kB │ gzip:   3.42 kB
dist/assets/_id-2fKv6VzY.js                              14.33 kB │ gzip:   4.30 kB
dist/assets/_auth-BSu99vcH.js                            15.56 kB │ gzip:   5.73 kB
dist/assets/accounts-B3pb1cJB.js                         23.72 kB │ gzip:   8.18 kB
dist/assets/GetTokens-BQBiQxi_.js                        39.29 kB │ gzip:  14.02 kB
dist/assets/settings-Crlgz8n9.js                         42.47 kB │ gzip:  12.20 kB
dist/assets/dashboard-ChKzKoQN.js                        51.05 kB │ gzip:  15.10 kB
dist/assets/button-Cd45O-27.js                           53.56 kB │ gzip:  18.71 kB
dist/assets/neurons-DPO1Ghk7.js                          66.03 kB │ gzip:  19.84 kB
dist/assets/voting-CZbyi3gJ.js                           69.22 kB │ gzip:  21.15 kB
dist/assets/neuronDetail-xWwPZCaj.js                     70.25 kB │ gzip:  21.00 kB
dist/assets/vendor-md-DL0JfF_R.js                        73.29 kB │ gzip:  19.98 kB
dist/assets/index-BiNc52CN.js                            79.79 kB │ gzip:  24.91 kB
dist/assets/vendor-tanstack-BZKtD_S5.js                 161.15 kB │ gzip:  49.35 kB
dist/assets/vendor-core-react-qLCIanUQ.js               189.81 kB │ gzip:  59.76 kB
dist/assets/vendor-recharts-Ck18_gYq.js                 223.45 kB │ gzip:  64.01 kB
dist/assets/vendor-icp-DP4ARddz.js                      411.37 kB │ gzip: 104.08 kB
dist/assets/vendor-libs-B2aYRUFu.js                     553.60 kB │ gzip: 180.31 kB

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR introduces a DOM-translation guard to prevent React commit-time crashes caused by in-browser translators (e.g., Google Translate) re-parenting text nodes, and installs it before the app mounts.

Changes:

  • Added installDomTranslationGuard() to patch Node.prototype.insertBefore / removeChild to avoid translator-induced NotFoundError crashes.
  • Installed the guard in main.tsx before mounting React.
  • Added Vitest coverage for the re-parented-node scenarios.

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 2 comments.

File Description
src/governance-app-frontend/src/main.tsx Installs the DOM translation guard before React mounts.
src/governance-app-frontend/src/common/utils/domTranslationGuard.ts Implements the insertBefore / removeChild hardening patch.
src/governance-app-frontend/src/common/utils/domTranslationGuard.spec.ts Adds unit tests for the translator re-parenting cases.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread src/governance-app-frontend/src/common/utils/domTranslationGuard.ts Outdated
Comment thread src/governance-app-frontend/src/common/utils/domTranslationGuard.spec.ts Outdated
yhabib added 2 commits July 13, 2026 15:04
In-browser page translators (Google Translate) rewrite text nodes by
wrapping them in their own <font> elements without React's knowledge.
React keeps references to the original nodes, so a later reconcile can
call insertBefore/removeChild against a node the translator re-parented,
throwing "Failed to execute 'insertBefore' on 'Node'" during commit and
crashing the route via the router error boundary. Users vote
successfully, then see "Something went wrong".

Install a one-time guard on Node.prototype.insertBefore/removeChild that
appends / no-ops when the reference/child isn't a child of the parent,
letting React's commit finish. Translation keeps working.
Instead of always appending when insertBefore's reference node isn't a
direct child, walk up to the ancestor that is still a child of the parent
(the translator's <font> wrapper) and insert before it, keeping the
intended position. Append only when no such ancestor exists.

Addresses review feedback.
@yhabib yhabib enabled auto-merge July 13, 2026 13:04
@yhabib yhabib force-pushed the fix/google-translate-insertbefore-crash branch from a967b45 to 11d4bba Compare July 13, 2026 13:04
@yhabib yhabib added this pull request to the merge queue Jul 13, 2026
Merged via the queue into main with commit 3c7e7f5 Jul 13, 2026
11 checks passed
@yhabib yhabib deleted the fix/google-translate-insertbefore-crash branch July 13, 2026 15:53
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants