{"record":{"id":"43e652eddb87258f","repo":"apache/druid","slug":"cannot-return-long-for-null-value-43e652","errorCode":null,"errorMessage":"Cannot return long for Null Value","messagePattern":"Cannot return long for Null Value","errorType":"exception","errorClass":"IllegalStateException","httpStatus":null,"severity":"error","filePath":"processing/src/main/java/org/apache/druid/query/aggregation/NullableNumericBufferAggregator.java","lineNumber":102,"sourceCode":"      return null;\n    }\n    return delegate.get(buf, position + Byte.BYTES);\n  }\n\n  @Override\n  public float getFloat(ByteBuffer buf, int position)\n  {\n    if (buf.get(position) == TypeStrategies.IS_NULL_BYTE) {\n      throw new IllegalStateException(\"Cannot return float for Null Value\");\n    }\n    return delegate.getFloat(buf, position + Byte.BYTES);\n  }\n\n  @Override\n  public long getLong(ByteBuffer buf, int position)\n  {\n    if (buf.get(position) == TypeStrategies.IS_NULL_BYTE) {\n      throw new IllegalStateException(\"Cannot return long for Null Value\");\n    }\n    return delegate.getLong(buf, position + Byte.BYTES);\n  }\n\n  @Override\n  public double getDouble(ByteBuffer buf, int position)\n  {\n    if (buf.get(position) == TypeStrategies.IS_NULL_BYTE) {\n      throw new IllegalStateException(\"Cannot return double for Null Value\");\n    }\n    return delegate.getDouble(buf, position + Byte.BYTES);\n  }\n\n  @Override\n  public boolean isNull(ByteBuffer buf, int position)\n  {\n    return buf.get(position) == TypeStrategies.IS_NULL_BYTE || delegate.isNull(buf, position + Byte.BYTES);\n  }","sourceCodeStart":84,"sourceCodeEnd":120,"githubUrl":"https://github.com/apache/druid/blob/9b90983fd291f26935af934383ce360473179e4d/processing/src/main/java/org/apache/druid/query/aggregation/NullableNumericBufferAggregator.java#L84-L120","documentation":"NullableNumericBufferAggregator keeps a null-marker byte in the ByteBuffer in front of each long value. getLong() throws IllegalStateException when that marker is IS_NULL_BYTE because a primitive long cannot represent null (0L would be ambiguous with a real zero).","triggerScenarios":"Calling getLong(buf, position) when the byte at `position` is TypeStrategies.IS_NULL_BYTE — the group never aggregated a non-null long value.","commonSituations":"Long aggregations in group-by queries where some groups have only null inputs; buffer layout bugs where reads don't skip the flag byte (position vs position + Byte.BYTES); custom aggregators integrated without the nullable wrapper's buffer protocol.","solutions":["Check agg.isNull(buf, position) before calling getLong()","Verify delegate reads use position + Byte.BYTES so the value, not the flag byte, is decoded","Ensure init()/putNull() in TypeStrategies initialize the marker byte for new group positions","If a group unexpectedly has no non-null values, that is a legitimate null result — handle it upstream instead of forcing a read"],"exampleFix":"// before\nlong v = agg.getLong(buf, position);\n// after\nLong v = agg.isNull(buf, position) ? null : agg.getLong(buf, position);","handlingStrategy":"validation","validationCode":"if (agg.isNull(buf, position)) {\n  return null;\n}","typeGuard":null,"tryCatchPattern":"try {\n  return agg.getLong(buf, position);\n} catch (IllegalStateException e) {\n  if (e.getMessage().contains(\"Cannot return long for Null Value\")) {\n    return null;\n  }\n  throw e;\n}","preventionTips":["Always read the marker byte at `position` and the value at position + Byte.BYTES — mixing up offsets corrupts both flag and value","Ensure init() writes IS_NULL_BYTE (or a valid marker) for every allocated slot","Audit custom buffer aggregators for the nullable wrapper's buffer protocol","Handle legitimate null groups in extraction code instead of forcing primitive reads"],"tags":["java","aggregation","bytebuffer","null-handling"],"backgroundTag":"internal-invariant-violation","analyzedSha":"9b90983fd291f26935af934383ce360473179e4d","analyzedAt":"2026-09-07T13:32:30.957Z","contentChangedAt":"2026-09-07T13:32:30.957Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}