apache/druid · error · IllegalStateException
written out already
Error message
written out already
What it means
V3CompressedVSizeColumnarMultiIntsSerializer serializes multi-valued int columns. Once the offsets stream has been finalized (`lastOffsetWritten` is true), no further rows may be added; addValues() throws this IllegalStateException to protect the already-committed serialization state.
Solutions
- Ensure all rows are added before closing/finalizing the serializer
- Create a fresh V3ComposedVSizeColumnarMultiIntsSerializer per column instead of reusing finished instances
- Fix retry/error-handling logic that may re-call addValues after a successful close
Example fix
// before serializer.close(); serializer.addValues(row); // throws // after serializer.close(); V3CompressedVSizeColumnarMultiIntsSerializer fresh = ...; // new serializer for new data fresh.addValues(row);
Defensive patterns
Strategy: validation
Validate before calling
if (!serializer.isClosed()) { serializer.addValues(row); } else { serializer = newSerializer(); serializer.addValues(row); } Try / catch
try { serializer.addValues(ints); } catch (IllegalStateException e) { throw new IOException("multi-int column already finalized; open a new serializer", e); } Prevention
- Add all rows before finalizing offsets
- One serializer per column/file
- Avoid re-calling addValues in retry paths after close
When it happens
Trigger: Calling addValues(IndexedInts) after the serializer was closed/finished; reusing the same serializer instance for a second column or file; aggregation feeding rows after finalization.
Common situations: Batch ingestion code that flushes a column then keeps appending rows; test harnesses reusing serializers across cases; error-handling paths that retry writes after 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
- Incompatible serializer for type
- written out already
- Actual Row count mismatch. Expected
- Attempt to add row to swapped-out sink for segment
- Column capacity exceeded
AI-assisted analysis of apache/druid@9b90983fd2 (2026-09-07).
Data as JSON: /api/errors/c0f5bd07ddefa3c1.
Report an issue: GitHub.
Appendix: source
Thrown at processing/src/main/java/org/apache/druid/segment/data/V3CompressedVSizeColumnarMultiIntsSerializer.java:113
{
this.columnName = columnName;
this.offsetWriter = offsetWriter;
this.valueWriter = valueWriter;
this.offset = 0;
}
@Override
public void open() throws IOException
{
offsetWriter.open();
valueWriter.open();
}
@Override
public void addValues(IndexedInts ints) throws IOException
{
if (lastOffsetWritten) {
throw new IllegalStateException("written out already");
}
offsetWriter.addValue(offset);
int numValues = ints.size();
for (int i = 0; i < numValues; i++) {
valueWriter.addValue(ints.get(i));
}
offset += numValues;
if (offset < 0) {
throw new ColumnCapacityExceededException(columnName);
}
}
@Override
public long getSerializedSize() throws IOException
{
writeLastOffset();
return 1 + offsetWriter.getSerializedSize() + valueWriter.getSerializedSize();
}View on GitHub (pinned to 9b90983fd2)