apache/druid · error · IllegalStateException

Writable channel is not available. The output channel might

Error message

Writable channel is not available. The output channel might be marked as read-only, hence no writes are allowed.

What it means

PartitionedOutputChannel wraps a per-partition OutputChannel; when created read-only the writable channel is never assigned (null). getWritableChannel() then throws ISE, because a producer is attempting to write to a channel that is explicitly marked read-only. Callers listed (openPartitionedChannel, runMerger, writableFrameChannel) are internal paths that only fetch it when writing is expected.

Source

Thrown at processing/src/main/java/org/apache/druid/frame/processor/PartitionedOutputChannel.java:91

      final MemoryAllocator frameMemoryAllocator,
      final Supplier<PartitionedReadableFrameChannel> readableChannelSupplier
  )
  {
    return new PartitionedOutputChannel(
        Preconditions.checkNotNull(writableChannel, "writableChannel"),
        Preconditions.checkNotNull(frameMemoryAllocator, "frameMemoryAllocator"),
        readableChannelSupplier
    );
  }

  /**
   * Returns the writable channel of this pair. The producer writes to this channel. Throws ISE if the output channel is
   * read only.
   */
  public synchronized WritableFrameChannel getWritableChannel()
  {
    if (writableChannel == null) {
      throw new ISE("Writable channel is not available. The output channel might be marked as read-only,"
                    + " hence no writes are allowed.");
    } else {
      return writableChannel;
    }
  }

  /**
   * Returns the memory allocator for the writable channel. The producer uses this to generate frames for the channel.
   * Throws ISE if the output channel is read only.
   */
  public synchronized MemoryAllocator getFrameMemoryAllocator()
  {
    if (frameMemoryAllocator == null) {
      throw new ISE("Frame allocator is not available. The output channel might be marked as read-only,"
                    + " hence memory allocator is not required.");
    } else {
      return frameMemoryAllocator;
    }

View on GitHub (pinned to 9b90983fd2)

Solutions

  1. Create the output channel with readOnly=false if producers must write to it.
  2. Check writableFrameChannel()/readOnly state before writing and route writes to the correct non-read-only channel.
  3. Ensure each partition's producer is wired to its own writable OutputChannel rather than a shared read-only one.

Example fix

// before
PartitionedOutputChannel out = new PartitionedOutputChannel(channels, readOnly);
out.getWritableChannel().write(frame);
// after
PartitionedOutputChannel out = new PartitionedOutputChannel(channels, false);
out.getWritableChannel().write(frame);
Defensive patterns

Strategy: try-catch

Validate before calling

if (outputChannel.isReadOnly()) {
  throw new IllegalStateException("Refusing to write to read-only output channel");
}

Type guard

boolean writable(PartitionedOutputChannel ch) { return !ch.isReadOnly(); }

Try / catch

try {
  WritableFrameChannel w = outputChannel.getWritableChannel();
} catch (IllegalStateException e) {
  // route writes to a writable channel or re-create with readOnly=false
}

Prevention

When it happens

Trigger: Constructing PartitionedOutputChannel with readOnly=true and later calling getWritableChannel(); sharing a read-only output channel across stages where one stage still tries to write frames to it.

Common situations: Query-stage wiring where an output is marked read-only (e.g. broadcast/read-only consumers) but a producer incorrectly targets it; tests reusing a read-only channel for writes; refactors that changed the readOnly flag without updating writers.

Understand the failure class

Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.

Related errors


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