apache/druid · critical · IllegalStateException
Bad null-marker byte, delegate class[%s]
Error message
Bad null-marker byte, delegate class[%s]
What it means
NullableNumericVectorAggregator.get() reads a one-byte null marker stored in the buffer in front of each aggregated value. Valid markers are IS_NULL_BYTE (return null) and IS_NOT_NULL_BYTE (delegate to the wrapped vector aggregator). Any other byte means the buffer contents are corrupted or misaligned, so an ISE including the delegate class name is thrown to expose the corruption immediately rather than decoding garbage as a number.
Source
Thrown at processing/src/main/java/org/apache/druid/query/aggregation/NullableNumericVectorAggregator.java:148
doAggregate(buf, j, vAggregationPositions, vAggregationRows, positionOffset);
} else {
doAggregate(buf, numRows, positions, rows, positionOffset);
}
}
@Override
@Nullable
public Object get(ByteBuffer buf, int position)
{
switch (buf.get(position)) {
case TypeStrategies.IS_NULL_BYTE:
return null;
case TypeStrategies.IS_NOT_NULL_BYTE:
return delegate.get(buf, position + Byte.BYTES);
default:
// Corrupted byte?
throw new ISE("Bad null-marker byte, delegate class[%s]", delegate.getClass().getName());
}
}
@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()
{
delegate.close();
}
private void doAggregate(ByteBuffer buf, int position, int start, int end)
{
buf.put(position, TypeStrategies.IS_NOT_NULL_BYTE);View on GitHub (pinned to 9b90983fd2)
Solutions
- Ensure every group-buffer slot is initialized via init()/putNull() so the marker byte is always written before get() is called
- Audit relocate()/copy logic so the null-marker byte moves together with the value
- Verify all delegate reads/writes use position + Byte.BYTES offsets consistently
- Check for version mismatches between the aggregation extension and core Druid that would change the buffer layout
Example fix
// before
return delegate.get(buf, position); // skips null marker entirely
// after
byte marker = buf.get(position);
if (marker == TypeStrategies.IS_NULL_BYTE) {
return null;
}
return delegate.get(buf, position + Byte.BYTES); Defensive patterns
Strategy: validation
Validate before calling
// defensive read of the marker before get()
byte marker = buf.get(position);
if (marker != TypeStrategies.IS_NULL_BYTE && marker != TypeStrategies.IS_NOT_NULL_BYTE) {
throw new IllegalStateException("Corrupted null-marker byte: " + marker);
} Try / catch
try {
return aggregator.get(buf, position);
} catch (ISE e) {
if (e.getMessage().startsWith("Bad null-marker byte")) {
LOG.error(e, "corrupted aggregation buffer at position %d", position);
return null; // or fail the query explicitly
}
throw e;
} Prevention
- Always initialize group-buffer slots (init/putNull) so the marker byte is never stale garbage
- Ensure relocate() copies the null-marker byte along with the value
- Use consistent position + Byte.BYTES offsets in all delegate calls
- Pin compatible versions of Druid core and any custom aggregation extensions sharing the buffer layout
When it happens
Trigger: A null-marker byte in the buffer holds neither TypeStrategies.IS_NULL_BYTE nor IS_NOT_NULL_BYTE — caused by buffer corruption, wrong position arithmetic (reading a value byte instead of the marker), uninitialized group slots, or a custom aggregator that doesn't follow the null-marker protocol.
Common situations: Custom TypeStrategies/vector aggregators that forget to write the marker byte on init; buffer relocation (relocate()) bugs that copy value bytes but not the flag byte; position off-by-one errors; mixed Druid versions or third-party aggregation extensions writing incompatible buffer layouts.
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 float for Null Value
- Cannot return long for Null Value
- Cannot return double for Null Value
- Not implemented
- Not implemented
AI-assisted analysis of apache/druid@9b90983fd2 (2026-09-07).
Data as JSON: /api/errors/d275e8eba1ead773.
Report an issue: GitHub.