apache/druid · error · IllegalArgumentException

startFrame[%,d] < 0

Error message

startFrame[%,d] < 0

What it means

ReadableFileFrameChannel reads a range of frames from a FrameFile. The constructor validates that startFrame is non-negative; a negative start frame is meaningless and throws IAE immediately. This is straightforward caller input validation.

Source

Thrown at processing/src/main/java/org/apache/druid/frame/channel/ReadableFileFrameChannel.java:59

  private final FrameFile frameFile;
  private final WireTransferable.ConcreteDeserializer deserializer;
  private final int endFrame;
  private int currentFrame;

  public ReadableFileFrameChannel(
      final FrameFile frameFile,
      final int startFrame,
      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);
  }

View on GitHub (pinned to 9b90983fd2)

Solutions

  1. Clamp startFrame to 0 before constructing the channel.
  2. Fix the computation producing the negative index (check partition arithmetic).
  3. Validate frame-range inputs at the configuration layer before creating the channel.

Example fix

// before
new ReadableFileFrameChannel(frameFile, deserializer, startFrame, endFrame); // startFrame = -1
// after
startFrame = Math.max(0, startFrame);
new ReadableFileFrameChannel(frameFile, deserializer, startFrame, endFrame);
Defensive patterns

Strategy: validation

Validate before calling

if (startFrame < 0) { throw new IllegalArgumentException("startFrame must be >= 0: " + startFrame); }

Type guard

boolean validStart(int startFrame) { return startFrame >= 0; }

Try / catch

try { new ReadableFileFrameChannel(f, d, startFrame, endFrame); } catch (IAE e) { if (e.getMessage().contains("startFrame") && e.getMessage().contains("< 0")) { startFrame = 0; /* retry */ } else { throw e; } }

Prevention

When it happens

Trigger: Constructing ReadableFileFrameChannel with startFrame < 0, e.g. passing -1 as a sentinel or computing a start index from an empty/underflowed counter.

Common situations: Off-by-one arithmetic producing -1 for the first partition; passing default/uninitialized partition metadata; int underflow when deriving frame 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


AI-assisted analysis of apache/druid@9b90983fd2 (2026-09-07). Data as JSON: /api/errors/506726b4bb23e09b. Report an issue: GitHub.