apache/druid · error · IllegalArgumentException
endFrame[%,d] > numFrames[%,d]
Error message
endFrame[%,d] > numFrames[%,d]
What it means
ReadableFileFrameChannel wraps a memory-mapped FrameFile and exposes frames [startFrame, endFrame) for reading. The constructor validates the requested frame range against the file and throws IAE when endFrame exceeds the number of frames actually present in the FrameFile. This guards against reading past the end of an immutable, on-disk frame file.
Source
Thrown at processing/src/main/java/org/apache/druid/frame/channel/ReadableFileFrameChannel.java:67
final int endFrame,
final WireTransferable.ConcreteDeserializer deserializer
)
{
this.frameFile = frameFile;
this.deserializer = deserializer;
this.currentFrame = startFrame;
this.endFrame = endFrame;
if (startFrame < 0) {
throw new IAE("startFrame[%,d] < 0", startFrame);
}
if (startFrame > endFrame) {
throw new IAE("startFrame[%,d] > endFrame[%,d]", startFrame, endFrame);
}
if (endFrame > frameFile.numFrames()) {
throw new IAE("endFrame[%,d] > numFrames[%,d]", endFrame, frameFile.numFrames());
}
}
public ReadableFileFrameChannel(
final FrameFile frameFile,
final WireTransferable.ConcreteDeserializer deserializer
)
{
this(frameFile, 0, frameFile.numFrames(), deserializer);
}
@Override
public boolean isFinished()
{
return currentFrame == endFrame;
}
@OverrideView on GitHub (pinned to 9b90983fd2)
Solutions
- Check frameFile.numFrames() before constructing and clamp endFrame to it.
- Verify the frame range was computed against the same FrameFile instance/version that is being opened.
- Use the two-argument constructor ReadableFileFrameChannel(frameFile, deserializer) to read all frames and avoid manual range math.
- Fix off-by-one logic: the range is [startFrame, endFrame), so endFrame may equal numFrames but not exceed it.
Example fix
// before
new ReadableFileFrameChannel(frameFile, start, end, deserializer);
// after
int safeEnd = Math.min(end, frameFile.numFrames());
if (safeEnd < start) { throw new IllegalArgumentException("empty range"); }
new ReadableFileFrameChannel(frameFile, start, safeEnd, deserializer); Defensive patterns
Strategy: validation
Validate before calling
if (frameFile.numFrames() == 0 || endFrame > frameFile.numFrames() || startFrame < 0 || startFrame > endFrame) {
throw new IllegalArgumentException("invalid frame range [" + startFrame + ", " + endFrame + ") numFrames=" + frameFile.numFrames());
} Try / catch
try { new ReadableFileFrameChannel(frameFile, start, end, deser); } catch (IllegalArgumentException e) { /* clamp range and retry */ } Prevention
- Always clamp ranges with Math.min(end, frameFile.numFrames())
- Remember the range is half-open [startFrame, endFrame)
- Compute ranges from the same FrameFile instance you open the channel with
When it happens
Trigger: Constructing ReadableFileFrameChannel(frameFile, startFrame, endFrame, deserializer) with endFrame > frameFile.numFrames(); e.g. splitting a frame file for parallel reads and computing sub-ranges from stale frame counts, or the frame file was rewritten/truncated with fewer frames after the range was computed.
Common situations: Off-by-one or exclusive-vs-inclusive range confusion when partitioning frames across workers; reading a frame file that was deleted or rewritten between counting frames and opening the channel; deserializing a persisted partition descriptor from an older run against a newly written file.
Understand the failure class
Background: "value must be between 0 and 1" / "out of range" / "must not be negative" errors: fixing range-validation failures across open-source libraries — this error's family across 42 libraries.
Related errors
- maxRetainedPartitionSketchBytes must be positive
- maxConcurrentStagesPerWorker must be positive
- Cannot handle column [%s] with type [%s]
- Cannot handle column [%s] with unknown type
- Cannot handle column [%s] with type [%s]
AI-assisted analysis of apache/druid@9b90983fd2 (2026-09-07).
Data as JSON: /api/errors/2a9d4eb40b32aa17.
Report an issue: GitHub.