@@ -412,10 +412,18 @@ export class RepeatBehavior<TSource = any> implements ViewBehavior, Subscriber {
412412 serializer ?? ( serializer = new XMLSerializer ( ) ) ;
413413 this . views = new Array ( itemCount ) ;
414414
415+ // Determine the scan boundary for this repeat directive.
416+ // Use the content binding boundaries (from the parent's fe:b/fe:/b
417+ // markers) to avoid scanning into sibling repeat blocks.
418+ const boundaries =
419+ isHydratable ( this . controller ) &&
420+ this . controller . bindingViewBoundaries [ this . directive . targetNodeId ] ;
421+ const scanStop : Node | null = boundaries ? boundaries . first : null ;
422+
415423 let current = this . location . previousSibling ;
416424 let itemIndex = itemCount - 1 ; // items render in order; walk backward
417425
418- while ( current !== null && itemIndex >= 0 ) {
426+ while ( current !== null && current !== scanStop && itemIndex >= 0 ) {
419427 if ( ! isCommentNode ( current ) || current . data !== "fe:/r" ) {
420428 current = current . previousSibling ;
421429 continue ;
@@ -425,17 +433,26 @@ export class RepeatBehavior<TSource = any> implements ViewBehavior, Subscriber {
425433 current . data = "" ;
426434 const end = current . previousSibling ;
427435 if ( ! end ) {
428- throw new Error (
436+ throw new HydrationRepeatError (
429437 `Error when hydrating inside "${
430438 ( this . location . getRootNode ( ) as ShadowRoot ) . host . nodeName
431439 } ": end should never be null.`,
440+ {
441+ index : itemIndex ,
442+ hydrationStage : "hydrateViews" ,
443+ itemsLength : itemCount ,
444+ viewsState : this . views . map ( v => ( v ? "hydrated" : "empty" ) ) ,
445+ rootNodeContent : getSerializer ( ) . serializeToString (
446+ this . location . getRootNode ( ) as any ,
447+ ) ,
448+ } ,
432449 ) ;
433450 }
434451
435452 // Find matching start marker via balanced counting
436453 let start : Node | null = end ;
437454 let depth = 0 ;
438- while ( start !== null ) {
455+ while ( start !== null && start !== scanStop ) {
439456 if ( isCommentNode ( start ) ) {
440457 if ( start . data === "fe:/r" ) {
441458 depth ++ ;
@@ -446,12 +463,11 @@ export class RepeatBehavior<TSource = any> implements ViewBehavior, Subscriber {
446463 current = startMarker . previousSibling ;
447464 const itemStart = startMarker . nextSibling ! ;
448465
449- // When the item is empty (start and end markers
450- // are adjacent), itemStart IS the cleared end
451- // marker and end IS the cleared start marker —
452- // an inverted range. Detect this by checking if
453- // end precedes itemStart in sibling order, and
454- // use itemStart as both first and last.
466+ // Empty item: start and end markers are adjacent
467+ // with no content between them. end === startMarker
468+ // because previousSibling of the end marker IS the
469+ // start marker. Use the cleared end marker comment
470+ // as both first and last for a valid single-node range.
455471 const itemEnd = end === startMarker ? itemStart : end ;
456472
457473 const view = template . hydrate ( itemStart , itemEnd ) ;
@@ -465,7 +481,7 @@ export class RepeatBehavior<TSource = any> implements ViewBehavior, Subscriber {
465481 }
466482 start = start . previousSibling ;
467483 }
468- if ( ! start ) {
484+ if ( ! start || start === scanStop ) {
469485 throw new HydrationRepeatError (
470486 `Error when hydrating inside "${
471487 ( this . location . getRootNode ( ) as ShadowRoot ) . host . nodeName
@@ -500,10 +516,11 @@ export class RepeatBehavior<TSource = any> implements ViewBehavior, Subscriber {
500516 ) ;
501517 }
502518
503- // Overflow check: detect extra repeat markers beyond items.length
504- if ( current !== null ) {
519+ // Overflow check: detect extra repeat markers beyond items.length,
520+ // bounded to this directive's scan range.
521+ if ( current !== null && current !== scanStop ) {
505522 let remaining : Node | null = current ;
506- while ( remaining !== null ) {
523+ while ( remaining !== null && remaining !== scanStop ) {
507524 if ( isCommentNode ( remaining ) && remaining . data === "fe:/r" ) {
508525 throw new HydrationRepeatError (
509526 `Error when hydrating inside "${
0 commit comments