apache/druid · error · IllegalStateException
Selection contained phantom row
Error message
Selection contained phantom row[%d]
What it means
FilteredVectorAggregator.aggregate() walks the filtered selection rows in lockstep with the underlying positions; if a selected row is not present in the underlying positions array (a 'phantom' row), the invariants are broken and it throws ISE. This indicates an internal inconsistency between the filter's selection and the vector's position tracking, not user data.
Solutions
- Disable vectorization for the query (set context 'vectorize': false) to confirm and work around
- Upgrade Druid — check release notes for fixed vector-filter bugs
- Inspect custom filter implementations for incorrect selection/position generation
Example fix
// before
POST /druid/v2 { "query": {...}, "context": {"vectorize": true} }
// after
POST /druid/v2 { "query": {...}, "context": {"vectorize": false} } Defensive patterns
Strategy: try-catch
Try / catch
try {
vectorAggregator.aggregate(buf, positions, offset, numPositions);
} catch (IllegalStateException e) {
if (e.getMessage() != null && e.getMessage().contains("phantom row")) {
log.error("Vector filter/aggregator invariant broken; rerun with vectorize=false", e);
} else {
throw e;
}
} Prevention
- Set context 'vectorize': false to work around vector-filter incompatibilities
- Keep Druid upgraded to pick up vector filter fixes
- Test custom VectorFilter implementations to ensure selections align with positions
When it happens
Trigger: Vectorized aggregation over a filtered vector cursor where the filter's selection contains row indexes absent from the delegate's rows array — typically an engine/filter incompatibility or bug in vector filter/position bookkeeping.
Common situations: Running vectorized queries with filters whose vectorized implementation mismatches the aggregator's expectations; custom vector filters; Druid version bugs in specific filter/vector combinations (workaround: disable vectorization).
Understand the failure class
Background: "This is a bug, please report it": internal invariant violations, unreachable panics, and SNH errors explained — this error's family across 47 libraries.
Related errors
- Bad null-marker byte, delegate class
- Can only handle [ ], got [ ]
- Can't add [ , ] to non-empty…
- Escape must be null or a single character
- Exceeded maximum allowed filters for CNF (conjunctive…
AI-assisted analysis of apache/druid@9b90983fd2 (2026-09-07).
Data as JSON: /api/errors/9d258864ee31502c.
Report an issue: GitHub.
Appendix: source
Thrown at processing/src/main/java/org/apache/druid/query/aggregation/FilteredVectorAggregator.java:120
match0 = VectorMatch.wrap(rows).setSelectionSize(numRows);
}
final ReadableVectorMatch match = matcher.match(match0, false);
final int[] selection = match.getSelection();
if (rows == null) {
for (int i = 0; i < match.getSelectionSize(); i++) {
delegatePositions[i] = positions[selection[i]];
}
} else {
// i iterates over the match; j iterates over the "rows" array
for (int i = 0, j = 0; i < match.getSelectionSize(); i++) {
for (; rows[j] < selection[i]; j++) {
// Do nothing; the for loop is doing the work of incrementing j.
}
if (rows[j] != selection[i]) {
throw new ISE("Selection contained phantom row[%d]", selection[i]);
}
delegatePositions[i] = positions[j];
}
}
delegate.aggregate(buf, match.getSelectionSize(), delegatePositions, selection, positionOffset);
}
@Override
public Object get(final ByteBuffer buf, final int position)
{
return delegate.get(buf, position);
}
@Override
public void close()
{View on GitHub (pinned to 9b90983fd2)