Dhanesh Dhakrey
10/23/2026, 4:54 AMOutOfMemoryError: Java heap space.
A jmap -histo:live shows the live heap is mostly String / Object[] / Long (~38 GB). A thread dump with no queries running shows thousands of parked MSE threads, the oldest ~21 days old:
• ~400 threads in LeafOperator.addResultsBlock → ArrayBlockingQueue.offer, each holding a full queue of `SelectionResultsBlock`s (~100 blocks, ~90–120 MB each);
• ~3,700 threads in SortedMailboxReceiveOperator / MailboxReceiveOperator waiting on child stages.
We can reproduce it on a single-node setup: every MSE JOIN query that times out on the broker leaves one leaf thread parked permanently (still there after 5.5 h, for queries with a 1.5–2 s timeout), holding its buffered rows. A query that completes leaves nothing behind. pinot.broker.enable.query.cancellation=true doesn't change this. SET maxStreamingPendingBlocks=10 shrinks each leak ~10× but doesn't stop it.
Is this a known issue, or fixed after 1.4.0? Happy to share thread dumps, histograms and the reproduction script.
Thankyou in Advance.Mayank
Gonzalo Ortiz
10/26/2026, 2:05 PMGonzalo Ortiz
10/26/2026, 2:11 PMextraPassiveTimeoutMs field, and the server adds it to the query timeout as if it were a duration. So every MSE wait on the server (leaf queue offer/poll, mailbox receive and send) gets a deadline about 55 years in the future and never times out. That one was fixed in github.com/apache/pinot/pull/16530.
Second, when a leaf stage is cancelled, LeafOperator interrupts the SSE thread once. That thread then tries to add the final “end of stream” block in a finally block. The queue is full and nobody reads it anymore, so the thread parks there forever with the whole queue of SelectionResultsBlocks. That is why maxStreamingPendingBlocks=10 makes each leak ~10x smaller without stopping it, and why enabling query cancellation does not help. That was fixed in github.com/apache/pinot/pull/16582 (plus a related cancellation fix in github.com/apache/pinot/pull/16625).
The real fix is to upgrade to 1.5.x. As a stopgap on 1.4.0, you can try adding SET extraPassiveTimeoutMs=1000; to your MSE queries. The dispatcher copies the query options over the broken value, so the servers get a real deadline back. I haven’t tested this on 1.4.0, so please check it with your reproduction script first.Mayank
kodalien kodalien
10/30/2026, 3:30 AM