apache/druid · error · IllegalStateException
Cannot return float for Null Value
Error message
Cannot return float for Null Value
What it means
NullableNumericBufferAggregator stores a null-flag byte alongside each aggregated value in an off-heap ByteBuffer. getFloat() checks that flag (TypeStrategies.IS_NULL_BYTE) at the given position and throws IllegalStateException if the value is null, because returning a primitive float would silently coerce null to 0.0f.
Source
Thrown at processing/src/main/java/org/apache/druid/query/aggregation/NullableNumericBufferAggregator.java:93
delegate.aggregate(buf, position + Byte.BYTES);
}
}
@Override
@Nullable
public Object get(ByteBuffer buf, int position)
{
if (buf.get(position) == TypeStrategies.IS_NULL_BYTE) {
return null;
}
return delegate.get(buf, position + Byte.BYTES);
}
@Override
public float getFloat(ByteBuffer buf, int position)
{
if (buf.get(position) == TypeStrategies.IS_NULL_BYTE) {
throw new IllegalStateException("Cannot return float for Null Value");
}
return delegate.getFloat(buf, position + Byte.BYTES);
}
@Override
public long getLong(ByteBuffer buf, int position)
{
if (buf.get(position) == TypeStrategies.IS_NULL_BYTE) {
throw new IllegalStateException("Cannot return long for Null Value");
}
return delegate.getLong(buf, position + Byte.BYTES);
}
@Override
public double getDouble(ByteBuffer buf, int position)
{
if (buf.get(position) == TypeStrategies.IS_NULL_BYTE) {
throw new IllegalStateException("Cannot return double for Null Value");View on GitHub (pinned to 9b90983fd2)
Solutions
- Call isNull(buf, position) first and skip getFloat() when it returns true
- Ensure the buffer aggregator reserves one extra byte (Byte.BYTES) for the null flag and reads the delegate at position + Byte.BYTES
- Check TypeStrategies/init() writes the correct null-marker byte for every newly allocated group slot
- Verify buffer relocation (relocate()) copies the null flag along with the value
Example fix
// before float v = agg.getFloat(buf, position); // after float v = agg.isNull(buf, position) ? 0.0f /* or handle null */ : agg.getFloat(buf, position);
Defensive patterns
Strategy: validation
Validate before calling
// before reading from the buffer
if (agg.isNull(buf, position)) {
return null; // or default
} Try / catch
try {
return agg.getFloat(buf, position);
} catch (IllegalStateException e) {
if (e.getMessage().contains("Cannot return float for Null Value")) {
return null;
}
throw e;
} Prevention
- Reserve the extra Byte.BYTES null-flag slot in buffer allocations and delegate at position + Byte.BYTES
- Initialize the null-marker byte for every new group position via TypeStrategies/init()
- Copy the marker byte during buffer relocation, not just the value
- Test with groups whose input rows are all null
When it happens
Trigger: Calling getFloat(buf, position) where the null-marker byte at `position` equals TypeStrategies.IS_NULL_BYTE — the group's aggregated value was never set to a non-null value.
Common situations: GroupBy v8 / buffer-based aggregation results where a group key exists but all its input rows had null values; buffer reorganization/relocation bugs that misalign the null-flag byte; custom buffer aggregators that don't reserve the extra null byte.
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
- Cannot return long for Null Value
- Cannot return double for Null Value
- Cannot return float for Null Value
- Cannot return long for Null Value
- Cannot return double for Null Value
AI-assisted analysis of apache/druid@9b90983fd2 (2026-09-07).
Data as JSON: /api/errors/5395f1171aa42bef.
Report an issue: GitHub.