Fix: Treat incomplete tree as an error during recovery (#36911)
In `recoverFromConcurrentError`, there's logic to determine if the latest render attempt resulted in another error or if it completed successfully, by checking whether the exit status matches RootErrored. The logic was incomplete because RootSuspendedAtTheShell is also considered an errored state in this context. This can cause an incomplete tree (i.e. one that unwinds without entering the complete phase) to be mistaken for a complete one, leading to confusing errors. An incomplete tree can never be committed because it's not guaranteed to represent a coherent state. An example of how this can manifest as a bug: in #33580, an error caught by an error boundary triggers a synchronous recovery render. During that render a parent component suspends on `use(thenable)` with no Suspense boundary above it, so the tree unwinds to the shell instead of completing. Because the incomplete tree is mistaken for a recovered one and committed, the parent fiber becomes current with a truncated hook list — only the hooks it rendered before suspending. On the next render it calls the rest of its hooks and throws "Rendered more hooks than during the previous render." Fixes #33580. Co-authored-by: Arunanshu Biswas <48434243+arunanshub@users.noreply.github.com> Co-authored-by: Arunanshu Biswas <48434243+arunanshub@users.noreply.github.com>
A
Andrew Clark committed
c3555f0ca2648380ccd3d6af23479610e72f6bf1
Parent: 2c8b735
Committed by GitHub <noreply@github.com>
on 6/30/2026, 7:38:59 PM