apache/druid · error · IllegalStateException

Cannot return double for Null Value

Error message

Cannot return double for Null Value

What it means

NullableNumericBufferAggregator's getDouble() inspects the null-marker byte stored before each double value in the ByteBuffer and throws IllegalStateException if the stored value is null. This preserves Druid's explicit null semantics instead of coercing null to 0.0 or NaN.

Source

Thrown at processing/src/main/java/org/apache/druid/query/aggregation/NullableNumericBufferAggregator.java:111

      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");
    }
    return delegate.getDouble(buf, position + Byte.BYTES);
  }

  @Override
  public boolean isNull(ByteBuffer buf, int position)
  {
    return buf.get(position) == TypeStrategies.IS_NULL_BYTE || delegate.isNull(buf, position + Byte.BYTES);
  }

  @Override
  public void relocate(int oldPosition, int newPosition, ByteBuffer oldBuffer, ByteBuffer newBuffer)
  {
    delegate.relocate(oldPosition + Byte.BYTES, newPosition + Byte.BYTES, oldBuffer, newBuffer);
  }

  @Override
  public void close()

View on GitHub (pinned to 9b90983fd2)

Solutions

  1. Query agg.isNull(buf, position) first and handle the null branch
  2. Confirm all delegate calls offset by position + Byte.BYTES to account for the flag byte
  3. Check relocate() copies both the marker byte and the value when buffers are reorganized
  4. For legitimately null groups, handle null in the result-extraction layer rather than reading the primitive

Example fix

// before
double v = agg.getDouble(buf, position);
// after
double v = agg.isNull(buf, position) ? Double.NaN /* or handle null */ : agg.getDouble(buf, position);
Defensive patterns

Strategy: validation

Validate before calling

if (agg.isNull(buf, position)) {
  return null;
}

Try / catch

try {
  return agg.getDouble(buf, position);
} catch (IllegalStateException e) {
  if (e.getMessage().contains("Cannot return double for Null Value")) {
    return null;
  }
  throw e;
}

Prevention

When it happens

Trigger: Calling getDouble(buf, position) where the null-flag byte at `position` equals TypeStrategies.IS_NULL_BYTE (group aggregated only null inputs).

Common situations: Double-typed group-by aggregations with all-null groups; buffer-alignment bugs (forgot Byte.BYTES offset when delegating); buffer corruptions from incorrect relocate()/copy logic moving value bytes without flag bytes.

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/55046da1a0d73d8f. Report an issue: GitHub.