apache/druid · error · IllegalStateException
Can't add [%d, %s] to non-empty SingleEntryShort2ObjectSorte
Error message
Can't add [%d, %s] to non-empty SingleEntryShort2ObjectSortedMap[%d, %s]
What it means
OvershadowableManager's internal SingleEntryShort2ObjectSortedMap can only hold one key/value pair. When a second entry with a different short key is added, it throws this IllegalStateException because the map has no capacity to grow — the caller must first convert the single-entry map to a full sorted map. It is an internal invariant violation indicating the bucket promotion logic should have run before the insert.
Source
Thrown at processing/src/main/java/org/apache/druid/timeline/partition/OvershadowableManager.java:1268
return key < 0 ? 0 : 1;
}
};
}
@Override
public V put(final short key, final V value)
{
if (isEmpty()) {
this.key = key;
this.val = value;
return null;
} else {
if (this.key == key) {
final V existing = this.val;
this.val = value;
return existing;
} else {
throw new ISE(
"Can't add [%d, %s] to non-empty SingleEntryShort2ObjectSortedMap[%d, %s]",
key,
value,
this.key,
this.val
);
}
}
}
@Override
public V get(short key)
{
return this.key == key ? val : null;
}
@Override
public V remove(final short key)View on GitHub (pinned to 9b90983fd2)
Solutions
- Ensure all adds to OvershadowableManager go through its synchronized/public API so the single-entry map is promoted to a multi-entry map when a second distinct key arrives
- Check for concurrent access to the same OvershadowableManager and add external synchronization if multiple threads can add partitions
- If constructing the map directly in tests, use a multi-entry Short2ObjectSortedMap implementation instead of the single-entry one
- Upgrade Druid — interleavings that produced this were fixed in later timeline-partition refactorings
Example fix
// before map.add((short) 5, chunkA); map.add((short) 7, chunkB); // throws: single-entry map // after OvershadowableManager<PartitionChunk<String>> mgr = OvershadowableManager.create(0); mgr.add(Partitions.makeChunk(chunkA)); mgr.add(Partitions.makeChunk(chunkB)); // manager promotes internally
Defensive patterns
Strategy: try-catch
Validate before calling
if (manager.canAddHolder() /* or check existing partitionIds first */) {
// safe to add
} Try / catch
try {
manager.add(chunk);
} catch (IllegalStateException e) {
if (e.getMessage() != null && e.getMessage().startsWith("Can't add")) {
// rebuild manager from snapshot / retry under lock
} else throw e;
} Prevention
- Only add partitions through OvershadowableManager's public synchronized API
- Synchronize external access if multiple threads add partitions to the same timeline bucket
- Never construct SingleEntryShort2ObjectSortedMap directly in application code
When it happens
Trigger: Calling OvershadowableManager.add with a partition whose partitionId differs from the one already held in the single-entry map, when the map was not promoted to a MultiEntry map first (e.g. add called in an unexpected interleaving without going through the promote logic).
Common situations: Concurrency bugs where two threads add partitions to the same OvershadowableManager simultaneously; custom code or tests constructing SingleEntryShort2ObjectSortedMap directly and inserting two distinct keys; version-specific regressions in segment publishing/overshadow tracking.
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
- No such stage[%s]
- Writable channel is not available. The output channel might
- Frame allocator is not available. The output channel might b
- Cannot have both awaitChannels and awaitFutures
- Expected single element
AI-assisted analysis of apache/druid@9b90983fd2 (2026-09-07).
Data as JSON: /api/errors/5349ba87790abc76.
Report an issue: GitHub.