You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
When a cardinality aggregation is used together with a hybrid query that has two or more subqueries, the dynamic pruning optimization in CardinalityAggregator can read past the end of a doc-values slice, producing an EOFException: read past EOF.
Root Cause
The dynamic pruning path in tryScoreWithPruningCollector assumes scorer/iterator semantics that the hybrid scorer (from the neural-search plugin) does not provide. When the pruning fails, the original code wraps the exception in an OpenSearchStatusException with RestStatus.INTERNAL_SERVER_ERROR, which:
Causes the entire shard to fail (_shards.failed > 0)
Returns HTTP 200 with silently truncated results
Clients that only check the HTTP status code never see the partial failure
Fix
Changed tryScoreWithPruningCollector to:
Log a warning instead of throwing an error when pruning fails
Return false to trigger the non-pruning fallback path in pickCollector
Close the pruning collector on all failure paths to prevent resource leaks
This means the cardinality aggregation will still compute correctly — just without the pruning optimization for the affected segment. The user sees the correct result instead of a silent partial failure.
When an exception occurs mid-way through bulkCollect, the pruningCollector may have already partially collected documents into shared aggregator state (e.g., counts/hashes) before the failure. Returning false to trigger the non-pruning fallback path will then re-collect those documents, potentially producing incorrect cardinality results (double counting) rather than the silent truncation described. Consider whether the pruning collector's mutations to aggregator state can be rolled back, or whether the fallback is only safe when the exception occurs before any collection has taken place.
} catch (Exceptione) {
Releasables.closeWhileHandlingException(pruningCollector);
logger.warn(
"Dynamic pruning failed for cardinality aggregation, falling back to non-pruning path. "
+ "You can set cluster setting [{}] to 0 to disable this optimization.",
CARDINALITY_AGGREGATION_PRUNING_THRESHOLD.getKey(),
e
);
returnfalse;
}
Catching Exception will also swallow CollectionTerminatedException and other control-flow exceptions that the aggregation framework relies on. Additionally, partial state may already be written into the pruning collector's internal counts before the failure, which could produce incorrect results if callers merge results. Consider catching only IOException/RuntimeException, and/or re-throwing CollectionTerminatedException and InterruptedException so shard cancellation still works.
+} catch (CollectionTerminatedException e) {+ throw e;
} catch (Exception e) {
Releasables.closeWhileHandlingException(pruningCollector);
logger.warn(
"Dynamic pruning failed for cardinality aggregation, falling back to non-pruning path. "
+ "You can set cluster setting [{}] to 0 to disable this optimization.",
CARDINALITY_AGGREGATION_PRUNING_THRESHOLD.getKey(),
e
);
return false;
}
Suggestion importance[1-10]: 6
__
Why: Valid concern: catching all Exception may swallow CollectionTerminatedException which is used for control flow in Lucene collectors. Re-throwing it preserves proper aggregation termination semantics, though the practical impact depends on whether such exceptions actually occur in this path.
Please examine the workflow log, locate, and copy-paste the failure(s) below, then iterate to green. Is the failure a flaky test unrelated to your change?
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Description
When a
cardinalityaggregation is used together with ahybridquery that has two or more subqueries, the dynamic pruning optimization inCardinalityAggregatorcan read past the end of a doc-values slice, producing anEOFException: read past EOF.Root Cause
The dynamic pruning path in
tryScoreWithPruningCollectorassumes scorer/iterator semantics that the hybrid scorer (from the neural-search plugin) does not provide. When the pruning fails, the original code wraps the exception in anOpenSearchStatusExceptionwithRestStatus.INTERNAL_SERVER_ERROR, which:_shards.failed > 0)Fix
Changed
tryScoreWithPruningCollectorto:falseto trigger the non-pruning fallback path inpickCollectorThis means the cardinality aggregation will still compute correctly — just without the pruning optimization for the affected segment. The user sees the correct result instead of a silent partial failure.
Related Issues
Closes #22582
Testing