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
- Fix the writer so add() is never called after close()/write-out; finish all adds first
- Check for double-close or reuse of a finished IncrementalIndex/segment writer
- If using custom plugin code, capture all values before closing the column
- 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
- Never call add() after close(); enforce ordering in wrapper code
- Avoid sharing serializers across threads without synchronization
- Create a new serializer per column/segment
- Add an isClosed flag to your ingestion pipeline
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.