fix(react-lang): stop ElementErrorBoundary from crashing the host with a commit-phase insertBefore error#744
Open
serhiizghama wants to merge 2 commits into
Conversation
…ldren The ElementErrorBoundary re-presented the previously rendered children on error (this.lastValidChildren). Those are element instances from an earlier render whose DOM React has already reconciled/moved, so re-inserting them desyncs the fiber tree from the live DOM and throws an uncatchable insertBefore error in React's commit phase, unmounting the whole subtree. Return null on error instead; the boundary still auto-recovers when new valid children arrive.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #727.
ElementErrorBoundarycatches a render error and then returnsthis.lastValidChildren— element instances captured from an earlier render. React has already reconciled and moved the DOM for those elements, so re-inserting them desyncs the fiber tree from the live DOM and throwsNotFoundError: Failed to execute 'insertBefore' on 'Node'in the commit phase. Because it's a mutation-phase error it can't be caught by a nested boundary — it escalates to the app root and unmounts the whole subtree. It shows up in streaming chat UIs and whenever a sibling re-render forces an already-renderedRenderersubtree to re-render.The fix is to render
nullon error rather than re-presenting the stale children. The boundary still auto-recovers as soon as new valid children arrive (the existingcomponentDidUpdatereset), so a transient streaming error clears on the next update instead of crashing. This matches the workaround the reporter verified. The trade-off is losing the "show last good state" for the one frame an element is broken, which seems well worth not tearing down the app — but happy to reconsider if you'd rather keep last-good-state via a keyed remount instead.The package had no test setup, so I added a jsdom vitest config and a regression test driving the boundary through error → recovery: it asserts the boundary renders nothing after a child throws (not the stale subtree) and recovers when valid children return. Confirmed it fails against the old
return this.lastValidChildren. typecheck/eslint/prettier clean.