apache/druid · error · ISE
Cannot have a null result!
Error message
Cannot have a null result!
What it means
FinalizeResultsQueryRunner post-processes query results, and for by-segment results it casts each input to a Result<BySegmentResultValueClass<T>>. The null check (an internal invariant) throws IllegalStateException when a null result reaches the finalize function — the value arrived as null even though the cast line executes first, so this check exists to fail loudly on a null that violates the runner's contract.
Solutions
- Find the upstream QueryRunner returning null results and make it return an empty Result or skip emission instead.
- Wrap custom runners so null results are filtered out before the finalize stage.
- Verify caching/merge configuration (by-segment query caching) isn't producing null entries in the results list.
Example fix
// before return results.isEmpty() ? null : new Result<>(...); // null leaks to finalize // after return new Result<>(timestamp, new BySegmentResultValueClass<>(results, segmentId, interval)); // always non-null
Defensive patterns
Strategy: try-catch
Validate before calling
if (input == null) {
// skip or substitute an empty result before feeding the finalize chain
} Try / catch
try {
Result<BySegmentResultValueClass<T>> r = finalize(input);
} catch (IllegalStateException e) {
if (e.getMessage().contains("Cannot have a null result")) {
// log and skip this result
} else { throw e; }
} Prevention
- Never return null Results from custom QueryRunners.
- Filter nulls out of merged result sequences before finalize.
- Test custom runners under by-segment caching.
When it happens
Trigger: A query tool/wrapper or custom QueryRunner upstream yields a null Result into the finalize chain when merging by-segment results (e.g. during caching or concatenation merges).
Common situations: Custom QueryRunner implementations or extensions that return null instead of an empty/absent result; query lifecycle bugs where a segment result was dropped but the pipeline still expected a Result object.
Related errors
- Cannot handle subquery
- Got a null list of results
- Got a null result! Segments are missing!
- Input is null
- Next token wasn't a START_ARRAY, was
AI-assisted analysis of apache/druid@9b90983fd2 (2026-09-07).
Data as JSON: /api/errors/07f79a9a762ea5c9.
Report an issue: GitHub.
Appendix: source
Thrown at processing/src/main/java/org/apache/druid/query/FinalizeResultsQueryRunner.java:92
metricManipulationFn = MetricManipulatorFns.identity();
}
if (isBySegment) {
finalizerFn = new Function<T, Result<BySegmentResultValue<T>>>()
{
final Function<T, T> baseFinalizer = toolChest.makePostComputeManipulatorFn(
query,
metricManipulationFn
);
@Override
public Result<BySegmentResultValue<T>> apply(T input)
{
//noinspection unchecked (input is not actually a T; see class-level javadoc)
Result<BySegmentResultValueClass<T>> result = (Result<BySegmentResultValueClass<T>>) input;
if (input == null) {
throw new ISE("Cannot have a null result!");
}
BySegmentResultValue<T> resultsClass = result.getValue();
final List<T> originalResults = resultsClass.getResults();
final ArrayList<T> transformedResults = new ArrayList<>(originalResults.size());
for (T originalResult : originalResults) {
transformedResults.add(baseFinalizer.apply(originalResult));
}
return new Result<>(
result.getTimestamp(),
new BySegmentResultValueClass<>(
transformedResults,
resultsClass.getSegmentId(),
resultsClass.getInterval()
)
);View on GitHub (pinned to 9b90983fd2)