apache/druid · error · IllegalStateException

written out already

Error message

written out already

What it means

BlockLayoutColumnarDoublesSerializer.add(double) appends a double to the block-based serializer. Once the serializer is closed (endBuffer nulled out by close/flush), it throws IllegalStateException('written out already') because writing after finalization would corrupt the segment file.

Source

Thrown at processing/src/main/java/org/apache/druid/segment/data/BlockLayoutColumnarDoublesSerializer.java:93

  }

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

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

  @Override
  public void add(double value) throws IOException
  {
    if (endBuffer == null) {
      throw new IllegalStateException("written out already");
    }
    if (!endBuffer.hasRemaining()) {
      endBuffer.rewind();
      flattener.write(endBuffer);
      endBuffer.clear();
    }

    endBuffer.putDouble(value);
    ++numInserted;
    if (numInserted < 0) {
      throw new ColumnCapacityExceededException(columnName);
    }
  }

  @Override
  public long getSerializedSize() throws IOException
  {
    writeEndBuffer();

View on GitHub (pinned to 9b90983fd2)

Solutions

  1. Ensure no add() calls occur after close()/write-out; finish all adds first
  2. Create a new serializer instance for each column/write session
  3. Check serializer state (endBuffer != null) before adding in defensive code

Example fix

// before
serializer.close();
serializer.add(value);
// after
serializer.add(value);
serializer.close();
Defensive patterns

Strategy: try-catch

Validate before calling

if (serializer != null && serializer.isOpen()) { serializer.add(value); }

Type guard

boolean canAdd(BlockLayoutColumnarDoublesSerializer s) { return s != null && s.isOpen(); } // if state accessor exists; otherwise track closed flag locally

Try / catch

try { serializer.add(value); } catch (IllegalStateException e) { throw new IOException("Serializer already closed; row count exceeded declared numRows", e); }

Prevention

When it happens

Trigger: Calling add() after close() (or after the serializer finished writing its last block and was written out), e.g. continuing to feed values after completing a column.

Common situations: Ingestion/task code paths that write more rows than declared; exception-handling bugs that retry add after close; reusing a serializer instance for a second column.

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/739e2df053e402f0. Report an issue: GitHub.