Skip to content

fix(desktop): recover root error boundary from transient render races (salvage #41787) - #52704

Merged
OutThisLife merged 1 commit into
mainfrom
bb/desktop-root-boundary-recover
Jun 25, 2026
Merged

fix(desktop): recover root error boundary from transient render races (salvage #41787)#52704
OutThisLife merged 1 commit into
mainfrom
bb/desktop-root-boundary-recover

Conversation

@OutThisLife

Copy link
Copy Markdown
Collaborator

What

Hermes Desktop could get stuck on the root "Reload window" screen after a transient assistant-ui render race. A just-shrunk thread rendered at a stale message index during a session switch / teardown throws errors like tapClientLookup: Index N out of bounds, Cannot read properties of undefined (reading 'type'), or Tried to unmount a fiber that is already unmounted. These bubble to the root ErrorBoundary and latch the whole app on the fallback even though the next render against fresh state would be fine.

Fix

The root boundary now treats that small set of known-transient renderer errors as recoverable: it logs them and schedules a next-tick reset() so React re-renders against current state instead of stranding the user.

Auto-recovery is bounded — at most MAX_RECOVERIES (3) attempts within a 5s window — so a genuinely persistent error can't spin the boundary in a reset -> throw -> reset loop; after the budget is spent the fallback is left up for the user. Manual retry (the button) resets the budget. Only the root boundary auto-recovers; scoped boundaries keep their own fallbacks, and unrecognized errors are never swallowed.

Tests

error-boundary.test.tsx:

  • a transient stale-index race recovers (fallback never sticks),
  • a persistent recoverable error stops at the cap and surfaces the fallback (proving the loop is bounded — without the cap this test would hang),
  • neither a non-root boundary nor an unrecognized root error auto-recovers.

tsc --noEmit clean, eslint clean, 4 tests green.

Credit

Closes #41693. Supersedes #41787 by @izumi0uu (credited via Co-authored-by), reimplemented with a bounded recovery budget so a non-transient error can't loop forever — addressing the symptom-only concern raised on the original PR.

…aces

A stale-index render race in assistant-ui (a just-shrunk thread rendered
at an old message index during a session switch / teardown) throws
errors like "tapClientLookup: Index N out of bounds", "Cannot read
properties of undefined (reading 'type')", or "Tried to unmount a fiber
that is already unmounted". These bubble to the root ErrorBoundary and
latch the WHOLE desktop app on the "Reload window" fallback even though
the next render against fresh state would be fine.

Teach the root boundary to treat that small set of known-transient
renderer errors as recoverable: log them and schedule a next-tick
reset() so React re-renders against current state instead of stranding
the user on the fallback.

Auto-recovery is BOUNDED -- at most MAX_RECOVERIES (3) attempts within a
5s window -- so a genuinely persistent error can't spin the boundary in
a reset -> throw -> reset loop; after the budget is spent the fallback
is left up for the user. Manual retry (the button) resets the budget.
Only the root boundary auto-recovers; scoped boundaries keep their own
fallbacks, and unrecognized errors are never swallowed.

Tests: transient race recovers (fallback never sticks), a persistent
recoverable error stops at the cap and surfaces the fallback (proving
the loop is bounded), and neither a non-root boundary nor an
unrecognized root error auto-recovers.

Closes #41693. Supersedes #41787 by @izumi0uu, reimplemented with a
bounded recovery budget so a non-transient error can't loop forever.

Co-authored-by: izumi0uu <izumi0uu@gmail.com>
@OutThisLife
OutThisLife enabled auto-merge June 25, 2026 21:16
@OutThisLife
OutThisLife merged commit c4ba477 into main Jun 25, 2026
21 checks passed
@OutThisLife
OutThisLife deleted the bb/desktop-root-boundary-recover branch June 25, 2026 21:17
@alt-glitch alt-glitch added type/bug Something isn't working comp/desktop Electron desktop app (apps/desktop/*) P3 Low — cosmetic, nice to have labels Jun 25, 2026
waefrebeorn pushed a commit to waefrebeorn/slermes that referenced this pull request Jul 2, 2026
…ot-boundary-recover

fix(desktop): recover root error boundary from transient render races (salvage NousResearch#41787)
habarmc1223-sudo pushed a commit to habarmc1223-sudo/hermes-agent-fluxmem that referenced this pull request Jul 8, 2026
…ot-boundary-recover

fix(desktop): recover root error boundary from transient render races (salvage NousResearch#41787)
santhreal pushed a commit to santhreal/hermes-agent that referenced this pull request Jul 13, 2026
…ot-boundary-recover

fix(desktop): recover root error boundary from transient render races (salvage NousResearch#41787)
Gravezzz pushed a commit to Gravezzz/hermes-agent that referenced this pull request Jul 21, 2026
…ot-boundary-recover

fix(desktop): recover root error boundary from transient render races (salvage NousResearch#41787)
leewenjie pushed a commit to leewenjie/hermes-agent that referenced this pull request Aug 7, 2026
…ot-boundary-recover

fix(desktop): recover root error boundary from transient render races (salvage NousResearch#41787)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

comp/desktop Electron desktop app (apps/desktop/*) P3 Low — cosmetic, nice to have type/bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug]: Hermes Desktop renderer crashes with "tapClientLookup: Index N out of bounds" → root error-boundary forces "Reload window"

2 participants