Skip to content

[OPIK-7435] [FE] Fix Google Translate removeChild crash on onboarding email step#7562

Merged
awkoy merged 2 commits into
mainfrom
awkoy/OPIK-7435-onboarding-email-translate-crash
Jul 22, 2026
Merged

[OPIK-7435] [FE] Fix Google Translate removeChild crash on onboarding email step#7562
awkoy merged 2 commits into
mainfrom
awkoy/OPIK-7435-onboarding-email-translate-crash

Conversation

@awkoy

@awkoy awkoy commented Jul 22, 2026

Copy link
Copy Markdown
Contributor

Details

Same class of crash as OPIK-7428, on the final onboarding step. Submitting the setup email on the mobile get-started onboarding throws:

NotFoundError: Failed to execute 'removeChild' on 'Node': The node to be removed is not a child of this node.

Reproduces when the browser auto-translates the page (Chrome, non-English locale, mobile viewport).

MobileOnboarding/ConnectStep.tsx renders the submit button label as a bare, state-dependent interpolated string (Email setup instructionsSending...Instructions sent!) sitting as a text sibling of the button icon. Chrome Translate wraps that text node in a <font> element; when the send handler flips state, React reconciles the button (icon swap + label change) against a node Translate re-parented and throws removeChild/insertBefore NotFoundError. Same mechanism as the WelcomeStep typewriter fix (see facebook/react#11538).

Fix: wrap the dynamic label in its own <span> — the canonical React + Google Translate fix. React now swaps a stable wrapper element (a direct child of the button) instead of a bare text node Translate re-parented. The label stays fully translatable (no translate="no" opt-out).

Also documents this crash class as a rule in .agents/skills/opik-frontend/SKILL.md (Critical Gotchas) so new dynamic/animated text wraps interpolated strings in an element — browser translation is common among our users.

Change checklist

  • User facing
  • Documentation update

Issues

OPIK-7435

AI-WATERMARK

AI-WATERMARK: yes

  • Tools: Claude Code
  • Model(s): Claude Opus 4.8
  • Scope: root-cause investigation and the one-element <span> wrap fix
  • Human verification: crash reported and reproduced on the mobile onboarding email step (Chrome translate); reviewer to confirm the fix on the same repro

Testing

  • ESLint clean (--max-warnings=0); TypeScript typecheck passes.
  • Manual: on a mobile viewport with Chrome page-translation on, advance to the last onboarding step and submit the email — no longer crashes; the label still translates.

Documentation

Added a rule to .agents/skills/opik-frontend/SKILL.md (Critical Gotchas → "Browser Translation Safety") describing the crash class and the wrap-in-element pattern.

… email step

The mobile ConnectStep submit button renders a state-dependent label
(Email setup instructions -> Sending... -> Instructions sent!) as a bare text
sibling of the button icon. Under browser translation Google Translate wraps
that text node in a <font> element; submitting the email reconciles the button
(icon + label swap) against a re-parented node and throws
"NotFoundError: Failed to execute 'removeChild' on 'Node'". Wrap the label in a
<span> so React swaps a stable wrapper element instead of the bare text node;
the label stays fully translatable. See react/react#11538.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@github-actions

github-actions Bot commented Jul 22, 2026

Copy link
Copy Markdown
Contributor

⏱️ pre-commit per-hook timing

Hook Description Result Duration
🌐 typecheck — frontend Whole-project tsc type check 42.03s
🌐 eslint — frontend Lint + autofix JS/TS 3.39s
Total (2 ran) 45.42s
⏭️ 39 skipped (no matching files changed)
Hook Description Result
🐍 trim trailing whitespace — python sdk Strip trailing whitespace ⏭️
🐍 fix end of files — python sdk Ensure files end in a newline ⏭️
🐍 ruff — python sdk Lint + autofix Python (ruff) ⏭️
🐍 ruff-format — python sdk Format Python code (ruff) ⏭️
🐍 mypy — python sdk Static type check ⏭️
🤖 trim trailing whitespace — optimizer Strip trailing whitespace ⏭️
🤖 fix end of files — optimizer Ensure files end in a newline ⏭️
🤖 check yaml — optimizer Validate YAML syntax ⏭️
🤖 check json — optimizer Validate JSON syntax ⏭️
🤖 check toml — optimizer Validate TOML syntax ⏭️
🤖 check for added large files — optimizer Block large files (>1MB) ⏭️
🔐 detect private key — optimizer Block committed private keys ⏭️
🤖 check for merge conflicts — optimizer Block merge-conflict markers ⏭️
🤖 check for case conflicts — optimizer Block case-only name clashes ⏭️
🤖 pyupgrade — optimizer Modernize Python syntax ⏭️
🤖 ruff — optimizer Lint + autofix Python (ruff) ⏭️
🤖 ruff-format — optimizer Format Python code (ruff) ⏭️
🤖 mypy — optimizer Static type check ⏭️
📓 nbstripout — optimizer notebooks Strip notebook output ⏭️
📝 markdownlint — optimizer Lint Markdown ⏭️
🔤 codespell — optimizer Fix common misspellings ⏭️
📊 radon cc — optimizer Cyclomatic-complexity gate ⏭️
📊 radon raw — optimizer Raw size metrics gate ⏭️
📊 xenon — optimizer Fail on complexity thresholds ⏭️
📊 lizard — optimizer Cyclomatic-complexity gate ⏭️
🧹 vulture — optimizer Find dead code ⏭️
🛡️ trim trailing whitespace — guardrails Strip trailing whitespace ⏭️
🛡️ fix end of files — guardrails Ensure files end in a newline ⏭️
🛡️ ruff — guardrails Lint + autofix Python (ruff) ⏭️
🛡️ ruff-format — guardrails Format Python code (ruff) ⏭️
🛡️ mypy — guardrails Static type check ⏭️
⚓ helm-docs Regenerate Helm chart README ⏭️
block non-public FE plugins Block non-public FE plugins ⏭️
☕ spotless — java backend Format Java code ⏭️
🧪 pre-commit wrapper smoke tests Self-test the wrapper scripts ⏭️
📘 eslint — typescript sdk Lint + autofix JS/TS ⏭️
📘 typecheck — typescript sdk Whole-project tsc type check ⏭️
⚙️ actionlint — github workflows Lint GitHub Actions workflows ⏭️
🐳 hadolint — dockerfiles Lint Dockerfiles ⏭️

@awkoy
awkoy requested a review from a team as a code owner July 22, 2026 09:45
@github-actions github-actions Bot added documentation Improvements or additions to documentation 🟢 size/S and removed 🔵 size/XS labels Jul 22, 2026
@awkoy
awkoy force-pushed the awkoy/OPIK-7435-onboarding-email-translate-crash branch from 137b8b6 to 696f0e1 Compare July 22, 2026 09:46
…text

Document the Google Translate removeChild crash class in the opik-frontend
skill (Critical Gotchas) so new dynamic/animated text wraps interpolated
strings in an element instead of rendering bare text nodes.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@awkoy
awkoy force-pushed the awkoy/OPIK-7435-onboarding-email-translate-crash branch from 696f0e1 to f293e03 Compare July 22, 2026 09:50
@awkoy
awkoy merged commit dc3af1c into main Jul 22, 2026
14 of 15 checks passed
@awkoy
awkoy deleted the awkoy/OPIK-7435-onboarding-email-translate-crash branch July 22, 2026 10:02
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentation Improvements or additions to documentation Frontend 🟢 size/S typescript *.ts *.tsx

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants