@@ -300,15 +300,30 @@ export class SpawnFrameScheduler {
300300 this . dirtyComponents . clear ( ) ;
301301
302302 const requestRenders = new Set < ( ) => void > ( ) ;
303+ const failed : SpawnFrameTarget [ ] = [ ] ;
304+
303305 for ( const component of batch ) {
304- // 1. Apply accumulated event state to rendering components
305- component . flushPendingUpdates ( ) ;
306- // 2. Invalidate render cache so render() recomputes on next TUI paint
307- component . clearRenderCache ( ) ;
308- // 3. Collect TUI invalidate
309- const r = component . flushScheduledRender ( ) ;
310- if ( r ) requestRenders . add ( r ) ;
306+ try {
307+ // 1. Apply accumulated event state to rendering components
308+ component . flushPendingUpdates ( ) ;
309+ // 2. Invalidate render cache so render() recomputes on next TUI paint
310+ component . clearRenderCache ( ) ;
311+ // 3. Collect TUI invalidate
312+ const r = component . flushScheduledRender ( ) ;
313+ if ( r ) requestRenders . add ( r ) ;
314+ } catch ( e ) {
315+ // Component failed during flush — re-queue for next frame.
316+ // The error is logged but we continue processing remaining components.
317+ console . error ( "[spawn] flush error on component:" , e ) ;
318+ failed . push ( component ) ;
319+ }
311320 }
321+
322+ // Re-queue failed components for recovery on next frame
323+ for ( const component of failed ) {
324+ getSingletons ( ) . frameScheduler . markDirty ( component ) ;
325+ }
326+
312327 // One invalidate per distinct callback per frame tick.
313328 for ( const requestRender of requestRenders ) {
314329 requestRender ( ) ;
0 commit comments