apache/druid · error · IllegalArgumentException

Invalid partition number [%d]

Error message

Invalid partition number [%d]

What it means

OutputChannel wraps a writable/readable frame channel pair with a partition number. Valid partition numbers are nonnegative, except the special sentinel NO_PARTITION (a negative reserved constant) meaning 'no partitioning'. Any other negative number is rejected by the constructor with IAE.

Source

Thrown at processing/src/main/java/org/apache/druid/frame/processor/OutputChannel.java:66

  private volatile MemoryAllocator frameMemoryAllocator;

  private final Supplier<ReadableFrameChannel> readableChannelSupplier;
  private final int partitionNumber;

  private OutputChannel(
      @Nullable final WritableFrameChannel writableChannel,
      @Nullable final MemoryAllocator frameMemoryAllocator,
      final Supplier<ReadableFrameChannel> readableChannelSupplier,
      final int partitionNumber
  )
  {
    this.writableChannel = writableChannel;
    this.frameMemoryAllocator = frameMemoryAllocator;
    this.readableChannelSupplier = readableChannelSupplier;
    this.partitionNumber = partitionNumber;

    if (partitionNumber < 0 && partitionNumber != WritableFrameChannel.NO_PARTITION) {
      throw new IAE("Invalid partition number [%d]", partitionNumber);
    }
  }

  /**
   * Creates an output channel pair, where the readable channel is not usable until writing is complete.
   *
   * @param writableChannel         writable channel for producer
   * @param frameMemoryAllocator    memory allocator for producer to use while writing frames to the channel
   * @param readableChannelSupplier readable channel for consumer. May be called multiple times, so you should wrap this
   *                                in {@link Suppliers#memoize} if needed.
   * @param partitionNumber         partition number, if any; may be {@link WritableFrameChannel#NO_PARTITION} if unknown
   */
  public static OutputChannel pair(
      final WritableFrameChannel writableChannel,
      final MemoryAllocator frameMemoryAllocator,
      final Supplier<ReadableFrameChannel> readableChannelSupplier,
      final int partitionNumber
  )

View on GitHub (pinned to 9b90983fd2)

Solutions

  1. Use WritableFrameChannel.NO_PARTITION explicitly instead of a hand-written negative number.
  2. Fix the arithmetic producing the negative partition number (guard partitionIndex before decrementing).
  3. Validate partition numbers before constructing OutputChannel when they come from external input.

Example fix

// before
new OutputChannel(writable, allocator, supplier, partitionIndex - 1);
// after
int partition = partitionIndex > 0 ? partitionIndex - 1 : WritableFrameChannel.NO_PARTITION;
new OutputChannel(writable, allocator, supplier, partition);
Defensive patterns

Strategy: validation

Validate before calling

if (partitionNumber < 0 && partitionNumber != WritableFrameChannel.NO_PARTITION) {
  throw new IllegalArgumentException("Invalid partition number: " + partitionNumber);
}

Type guard

boolean validPartition(int p) { return p >= 0 || p == WritableFrameChannel.NO_PARTITION; }

Try / catch

try {
  out = new OutputChannel(writable, allocator, supplier, partition);
} catch (IllegalArgumentException e) {
  // fall back to NO_PARTITION sentinel
}

Prevention

When it happens

Trigger: Calling `new OutputChannel(..., -1, ...)` or with a negative partition number computed by subtraction (e.g. partitionIndex - 1 at index 0), where NO_PARTITION was intended but the sentinel constant wasn't used.

Common situations: Off-by-one in partition counters; using a magic negative value like -1 that does not match WritableFrameChannel.NO_PARTITION; deserializing partition numbers from config where they came out negative.

Related errors


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