Bitmap intersection rescan: "stream (consumer N, segment X) claimed twice" on 0.25.6
Summary
On paradedb/paradedb:0.25.6-pg18, a query that combines a BM25 @@@ search with a heap-filter predicate covered by a btree index fails with:
InternalServerError: bitmap intersection stream (consumer 0, segment <uuid>) claimed twiceThe segment UUID differs on every failure → a rescan state-reset bug, not a corrupted index.
Environment
- Image:
paradedb/paradedb:0.25.6-pg18(Postgres 18 + pg_search) - The error is still present on 0.25.6, which already includes both #6118 (
fix: Bitmap intersection children were dropped by CustomPathBuilder::build on 0.25.x, 2026-08-27, merged before the 0.25.6 tag) and #6092 (per-rescan DSA free). So this appears to be a separate, still-unfixed bitmap-intersection rescan issue. - Not fixed in
v0.25.9either (checked the release commit history — no bitmap-intersection / claimed-twice related commit).
Reproduction
SET paradedb.enable_bitmap_intersection = on; -- default
EXPLAIN (COSTS OFF)
SELECT id FROM memory_units
WHERE bank_id = 'Agent::NAS-Docker' AND fact_type = 'observation'
AND id @@@ paradedb.boolean(should => ARRAY[
paradedb.match('text', '测试'),
paradedb.match('context', '测试'),
paradedb.match('text_signals', '测试')])
ORDER BY paradedb.score(id) DESC LIMIT 10;Plan (note the bitmap intersection path):
Limit
-> Custom Scan (ParadeDB Base Scan) on memory_units
Index: idx_memory_units_text_search
Bitmap Intersection: idx_memory_units_bank_fact_type <-- triggers the bug
"uses_tid_bitmap":true,"bitmap_consumer_id":0
"uses_tid_bitmap":true,"bitmap_consumer_id":1The bitmap_consumer_id in the plan is exactly the consumer N in the error — it is a bitmap consumer, not a parallel worker (this was initially misdiagnosed as a parallel-scan issue; it is not).
In our workload this scan sits on the inner side of a nested loop and is rescanned repeatedly, which is when the error fires.
Root cause (hypothesis)
bank_id = ? AND fact_type = ? is covered by the btree index idx_memory_units_bank_fact_type, so pg_search builds a bitmap from it to pre-filter documents (the paradedb.enable_bitmap_intersection feature, default on). On rescan of the custom scan, the bitmap-intersection stream / consumer state is not reset correctly, so the same segment is consumed twice → claimed twice.
Workaround
Two settings are required together. Disabling only bitmap_intersection makes the planner pick a parallel plan, which then hits a separate unfixed race (paradedb#6112, not cherry-picked into 0.25.x) that silently returns duplicated rows:
SET paradedb.enable_bitmap_intersection = off;
SET max_parallel_workers_per_gather = 0;After both are set, EXPLAIN shows a clean serial Custom Scan with always_filters heap filtering (no Bitmap Intersection, no Gather). The query then runs correctly.
Suggested fix
On rescan of a ParadeDB base scan that uses bitmap intersection, fully re-initialize / reset the bitmap-intersection stream and consumer state before each rescan, rather than reusing the prior state.
Related
- #6118 — "Bitmap intersection children were dropped by CustomPathBuilder::build" (already in 0.25.6; does not fix this)
- #6092 — "Bitmap intersection: free the per-rescan DSA allocation" (a different per-rescan issue)
- paradedb#6112 — parallel rescan race (not in 0.25.x; the reason the workaround above also needs
max_parallel_workers_per_gather=0)
Source: paradedb/paradedb