@@ -63,7 +63,18 @@ func (q *DeliveryScanQueryByID) QueryByID(ctx context.Context, startingBlock dri
6363 // Keys are supposed to be unique
6464 keys := collections .Keys (evicted ) // These are the state keys we are looking for
6565 ch := make (chan []KeyInfo , len (keys ))
66- go q .queryByID (ctx , keys , ch , startingBlock , evicted )
66+
67+ go func () {
68+ // Defense in depth: any unforeseen panic in this background path must degrade to a
69+ // failed request rather than crashing the whole node process, since nothing else in
70+ // this goroutine's call chain has a recover().
71+ defer func () {
72+ if r := recover (); r != nil {
73+ logger .Errorf ("recovered from panic in queryByID: %v" , r )
74+ }
75+ }()
76+ q .queryByID (ctx , keys , ch , startingBlock , evicted )
77+ }()
6778
6879 return ch , nil
6980}
@@ -114,6 +125,13 @@ func (q *DeliveryScanQueryByID) queryByID(ctx context.Context, keys []driver.PKe
114125
115126 continue
116127 }
128+ if len (values ) != len (keys ) {
129+ logger .Errorf ("peer returned %d values for %d keys in ns [%s]; falling back to block scan" ,
130+ len (values ), len (keys ), ns )
131+ startDelivery = true
132+
133+ continue // treat as a per-namespace failure (=> fall back to the slow block scan)
134+ }
117135 found := make ([]KeyInfo , 0 , len (values ))
118136 var notFound []string
119137 for i , value := range values {
0 commit comments