apache/druid · error · IllegalStateException
written out already
Error message
written out already
What it means
BlockLayoutColumnarLongsSerializer.add(long) throws IllegalStateException("written out already") when the serializer was already closed: endBuffer is null after the column data has been written out. Adds after close violate the serializer's lifecycle and would corrupt the segment, so the call fails fast.
Source
Thrown at processing/src/main/java/org/apache/druid/segment/data/BlockLayoutColumnarLongsSerializer.java:102
}
@Override
public void open() throws IOException
{
flattener.open();
}
@Override
public int size()
{
return numInserted;
}
@Override
public void add(long value) throws IOException
{
if (endBuffer == null) {
throw new IllegalStateException("written out already");
}
if (numInserted == numInsertedForNextFlush) {
numInsertedForNextFlush += sizePer;
writer.flush();
endBuffer.flip();
flattener.write(endBuffer);
endBuffer.clear();
writer.setBuffer(endBuffer);
}
writer.write(value);
++numInserted;
if (numInserted < 0) {
throw new ColumnCapacityExceededException(columnName);
}
}
@OverrideView on GitHub (pinned to 9b90983fd2)
Solutions
- Ensure all add(long) calls complete before closing the serializer/segment
- Audit custom code for lifecycle violations (add-after-close)
- Avoid reusing serializer instances across multiple segments
- Add a defensive 'open' flag in wrapper code to detect late adds
Example fix
// before longSerializer.add(value); // after close // after assert !isClosed : "serializer already written out"; longSerializer.add(value);
Defensive patterns
Strategy: validation
Validate before calling
if (closed) {
throw new IllegalStateException("Cannot add long values after serializer close");
} Try / catch
try {
serializer.add(value);
} catch (IllegalStateException e) {
if ("written out already".equals(e.getMessage())) {
throw new IllegalStateException("Lifecycle bug: add(long) after close", e);
}
throw e;
} Prevention
- Finish all adds before closing the column
- Never reuse closed serializers
- Synchronize concurrent writers
- Assert lifecycle order in plugin tests
When it happens
Trigger: Calling add(long) after close() or after the underlying WriteOutBytes was flushed and buffers nulled during segment serialization.
Common situations: Custom extension code writing rows after segment close; reusing a finished column serializer; race conditions in concurrent ingestion plugins.
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/0afcc48484f5d0f4.
Report an issue: GitHub.