apache/druid · error · IllegalStateException

written out already

Error message

written out already

What it means

BlockLayoutColumnarFloatsSerializer.add(float) throws IllegalStateException("written out already") when the serializer has already been closed out (endBuffer set to null after the column was written). After close/serialization the serializer no longer accepts values. This is a lifecycle-state violation, not an I/O error.

Source

Thrown at processing/src/main/java/org/apache/druid/segment/data/BlockLayoutColumnarFloatsSerializer.java:94

  }

  @Override
  public void open() throws IOException
  {
    flattener.open();
  }

  @Override
  public int size()
  {
    return numInserted;
  }

  @Override
  public void add(float value) throws IOException
  {
    if (endBuffer == null) {
      throw new IllegalStateException("written out already");
    }
    if (!endBuffer.hasRemaining()) {
      endBuffer.rewind();
      flattener.write(endBuffer);
      endBuffer.clear();
    }
    endBuffer.putFloat(value);
    ++numInserted;
    if (numInserted < 0) {
      throw new ColumnCapacityExceededException(columnName);
    }
  }

  @Override
  public long getSerializedSize() throws IOException
  {
    writeEndBuffer();
    return META_SERDE_HELPER.size(this) + flattener.getSerializedSize();

View on GitHub (pinned to 9b90983fd2)

Solutions

  1. Fix the writer so add() is never called after close()/write-out; finish all adds first
  2. Check for double-close or reuse of a finished IncrementalIndex/segment writer
  3. If using custom plugin code, capture all values before closing the column
  4. Guard with an internal flag so callers cannot add after finalize

Example fix

// before
serializer.add(value); // may run after close()
// after
if (!closed) {
  serializer.add(value);
}
Defensive patterns

Strategy: validation

Validate before calling

// guard the lifecycle before adding
if (serializer == null || isClosed(serializer)) {
  throw new IllegalStateException("Attempt to add after serializer close");
}

Try / catch

try {
  serializer.add(value);
} catch (IllegalStateException e) {
  if (e.getMessage().contains("written out already")) {
    // open a fresh serializer and replay the value
    serializer = newSerializer();
    serializer.add(value);
  } else throw e;
}

Prevention

When it happens

Trigger: Calling add(float) after close() or after the serializer's buffers were written out via a WriteOutBytes flush — endBuffer is null at that point.

Common situations: Custom ingestion/indexing code that keeps a serializer reference alive after finalizing the column; bugs in custom plugins (e.g., custom aggregations or extensions) that write rows out of order or after segment close.

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/8072f5f04217464d. Report an issue: GitHub.