apache/druid · error · IllegalArgumentException
Partitions must all abut each other
Error message
Partitions must all abut each other
What it means
FrameChannelMerger optimizes merging by only inspecting the earliest and latest key of the supplied ClusterByPartitions. That shortcut is only correct if the partition ranges have no gaps between them, so the constructor verifies partitionsToUse.allAbutting() and throws IAE otherwise. Callers must supply contiguous partition bounds.
Source
Thrown at processing/src/main/java/org/apache/druid/frame/processor/FrameChannelMerger.java:123
final WritableFrameChannel outputChannel,
final FrameWriterFactory frameWriterFactory,
final List<KeyColumn> sortKey,
@Nullable final FrameCombiner combiner,
@Nullable final ClusterByPartitions partitions,
final long rowLimit
)
{
if (inputChannels.isEmpty()) {
throw new IAE("Must have at least one input channel");
}
final ClusterByPartitions partitionsToUse =
partitions == null ? ClusterByPartitions.oneUniversalPartition() : partitions;
if (!partitionsToUse.allAbutting()) {
// To simplify merging logic, when frames we only look at the earliest and latest key in "partitions". To ensure
// correctness, we need to verify that there are no gaps.
throw new IAE("Partitions must all abut each other");
}
if (!sortKey.stream().allMatch(keyColumn -> keyColumn.order().sortable())) {
throw new IAE("Key is not sortable");
}
this.inputChannels = inputChannels;
this.outputChannel = outputChannel;
this.frameReader = frameReader;
this.frameWriterFactory = frameWriterFactory;
this.sortKey = sortKey;
this.partitions = partitionsToUse;
this.rowLimit = rowLimit;
this.currentFrames = new FramePlus[inputChannels.size()];
this.remainingChannels = new IntAVLTreeSet(IntSets.fromTo(0, inputChannels.size()));
this.tournamentTree = new TournamentTree(
inputChannels.size(),
(k1, k2) -> {View on GitHub (pinned to 9b90983fd2)
Solutions
- Use partition bounds produced by the standard clustering/partitioning code (e.g. from a previous ClusterBy stage) so ranges are contiguous.
- Validate ClusterByPartitions.allAbutting() before constructing the merger and repair gaps or use the full set.
- If partitions came from a filtered set, merge adjacent ranges or reject the set instead of passing it to the merger.
Example fix
// before
FrameChannelMerger merger = new FrameChannelMerger(allocator, sortKey, channels, null, filteredPartitions, rowLimit);
// after
if (!filteredPartitions.allAbutting()) {
throw new IllegalStateException("Partitions have gaps; cannot merge: " + filteredPartitions);
}
FrameChannelMerger merger = new FrameChannelMerger(allocator, sortKey, channels, null, filteredPartitions, rowLimit); Defensive patterns
Strategy: validation
Validate before calling
if (partitions != null && !partitions.allAbutting()) {
throw new IllegalArgumentException("Partitions have gaps: " + partitions);
} Type guard
boolean mergeable(ClusterByPartitions p) { return p == null || p.allAbutting(); } Try / catch
try {
merger = new FrameChannelMerger(allocator, sortKey, channels, null, partitions, rowLimit);
} catch (IllegalArgumentException e) {
// regenerate partition bounds contiguously
} Prevention
- Always derive partition bounds from the standard partitioning stages.
- Never filter partitions without re-checking contiguity.
- Call allAbutting() as a precondition before merge operations.
When it happens
Trigger: Constructing a FrameChannelMerger with a ClusterByPartitions whose ranges do not abut, e.g. partitions [0,10) and [20,30) with a gap (10,20), typically from manually built partition bounds or bounds filtered after generation.
Common situations: Custom partition-bound construction in stage/worker assignment code; dropping intermediate partitions when a worker fails; passing user-derived partition boundaries that skip ranges.
Understand the failure class
Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.
Related errors
- Invalid partition number [%d]
- Invalid stageNumber [%s]
- Only positive integers or zero can be added
- Cannot have null or empty column name
- Must have at least one input channel
AI-assisted analysis of apache/druid@9b90983fd2 (2026-09-07).
Data as JSON: /api/errors/b48a1d2d4f10634a.
Report an issue: GitHub.