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

  1. Call isNull(buf, position) first and skip getFloat() when it returns true
  2. Ensure the buffer aggregator reserves one extra byte (Byte.BYTES) for the null flag and reads the delegate at position + Byte.BYTES
  3. Check TypeStrategies/init() writes the correct null-marker byte for every newly allocated group slot
  4. 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

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


AI-assisted analysis of apache/druid@9b90983fd2 (2026-09-07). Data as JSON: /api/errors/5395f1171aa42bef. Report an issue: GitHub.