@@ -4438,9 +4438,15 @@ function erroredTask(
44384438const boundaryRow = boundary . row ;
44394439if ( boundaryRow !== null ) {
44404440// Unblock the SuspenseListRow that was blocked by this boundary.
4441+ // finishSuspenseListRow → unblockSuspenseListRow → finishedTask reenters
4442+ // and decrements allPendingTasks. Pin the counter above zero so those
4443+ // nested calls can't trip completeAll before this outer frame's own
4444+ // zero check at the end.
4445+ request . allPendingTasks ++ ;
44414446if ( -- boundaryRow . pendingTasks === 0 ) {
44424447finishSuspenseListRow ( request , boundaryRow ) ;
44434448}
4449+ request . allPendingTasks -- ;
44444450}
44454451
44464452// Regardless of what happens next, this boundary won't be displayed,
@@ -4955,20 +4961,21 @@ function finishedTask(
49554961hoistHoistables ( boundaryRow . hoistables , boundary . contentState ) ;
49564962}
49574963if ( ! isEligibleForOutlining ( request , boundary ) ) {
4958- // abortTaskSoft reenters finishedTask for each aborted task, which
4959- // decrements allPendingTasks. Ensure that these reentrant finsihedTask
4960- // calls do not call `completeAll` too early by forcing the task counter
4961- // above zero for their duration.
4964+ // abortTaskSoft (below) and finishSuspenseListRow → unblockSuspenseListRow
4965+ // → finishedTask (further below) both reenter finishedTask and decrement
4966+ // allPendingTasks. Pin the counter above zero for the duration of these
4967+ // fan-outs so a nested finishedTask can't observe 0 and call completeAll
4968+ // before this outer call reaches its own zero check.
49624969request . allPendingTasks ++ ;
49634970boundary . fallbackAbortableTasks . forEach ( abortTaskSoft , request ) ;
49644971boundary . fallbackAbortableTasks . clear ( ) ;
4965- request . allPendingTasks -- ;
49664972if ( boundaryRow !== null ) {
49674973// If we aren't eligible for outlining, we don't have to wait until we flush it.
49684974if ( -- boundaryRow . pendingTasks === 0 ) {
49694975finishSuspenseListRow ( request , boundaryRow ) ;
49704976}
49714977}
4978+ request . allPendingTasks -- ;
49724979}
49734980
49744981if (
@@ -4994,11 +5001,17 @@ function finishedTask(
49945001boundaryRow . next ,
49955002) ;
49965003}
5004+ // finishSuspenseListRow → unblockSuspenseListRow → finishedTask reenters
5005+ // and decrements allPendingTasks. Pin the counter above zero so those
5006+ // nested calls can't trip completeAll before this outer frame's own
5007+ // zero check at the end.
5008+ request . allPendingTasks ++ ;
49975009if ( -- boundaryRow . pendingTasks === 0 ) {
49985010// This is really unnecessary since we've already postponed the boundaries but
49995011// for pairity with other track+finish paths. We might end up using the hoisting.
50005012finishSuspenseListRow ( request , boundaryRow ) ;
50015013}
5014+ request . allPendingTasks -- ;
50025015}
50035016}
50045017} else {
0 commit comments