{"record":{"id":"c0f5bd07ddefa3c1","repo":"apache/druid","slug":"written-out-already-c0f5bd","errorCode":null,"errorMessage":"written out already","messagePattern":"written out already","errorType":"exception","errorClass":"IllegalStateException","httpStatus":null,"severity":"error","filePath":"processing/src/main/java/org/apache/druid/segment/data/V3CompressedVSizeColumnarMultiIntsSerializer.java","lineNumber":113,"sourceCode":"  {\n    this.columnName = columnName;\n    this.offsetWriter = offsetWriter;\n    this.valueWriter = valueWriter;\n    this.offset = 0;\n  }\n\n  @Override\n  public void open() throws IOException\n  {\n    offsetWriter.open();\n    valueWriter.open();\n  }\n\n  @Override\n  public void addValues(IndexedInts ints) throws IOException\n  {\n    if (lastOffsetWritten) {\n      throw new IllegalStateException(\"written out already\");\n    }\n    offsetWriter.addValue(offset);\n    int numValues = ints.size();\n    for (int i = 0; i < numValues; i++) {\n      valueWriter.addValue(ints.get(i));\n    }\n    offset += numValues;\n    if (offset < 0) {\n      throw new ColumnCapacityExceededException(columnName);\n    }\n  }\n\n  @Override\n  public long getSerializedSize() throws IOException\n  {\n    writeLastOffset();\n    return 1 + offsetWriter.getSerializedSize() + valueWriter.getSerializedSize();\n  }","sourceCodeStart":95,"sourceCodeEnd":131,"githubUrl":"https://github.com/apache/druid/blob/9b90983fd291f26935af934383ce360473179e4d/processing/src/main/java/org/apache/druid/segment/data/V3CompressedVSizeColumnarMultiIntsSerializer.java#L95-L131","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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"],"exampleFix":"// before\nserializer.close();\nserializer.addValues(row); // throws\n// after\nserializer.close();\nV3CompressedVSizeColumnarMultiIntsSerializer fresh = ...; // new serializer for new data\nfresh.addValues(row);","handlingStrategy":"validation","validationCode":"if (!serializer.isClosed()) { serializer.addValues(row); } else { serializer = newSerializer(); serializer.addValues(row); }","typeGuard":null,"tryCatchPattern":"try { serializer.addValues(ints); } catch (IllegalStateException e) { throw new IOException(\"multi-int column already finalized; open a new serializer\", e); }","preventionTips":["Add all rows before finalizing offsets","One serializer per column/file","Avoid re-calling addValues in retry paths after close"],"tags":["druid","segment","serialization"],"backgroundTag":"invalid-state-transition","analyzedSha":"9b90983fd291f26935af934383ce360473179e4d","analyzedAt":"2026-09-07T13:32:30.957Z","contentChangedAt":"2026-09-07T13:32:30.957Z","schemaVersion":2},"datasetVersion":"2026-09-17T15:17:12.973Z"}