{"record":{"id":"02ad053cd18b8b6a","repo":"apache/druid","slug":"value-dictionaries-already-serialized-for-column","errorCode":null,"errorMessage":"Value dictionaries already serialized for column [%s], cannot serialize again","messagePattern":"Value dictionaries already serialized for column \\[(.+?)\\], cannot serialize again","errorType":"exception","errorClass":"org.apache.druid.java.util.common.ISE","httpStatus":null,"severity":"error","filePath":"processing/src/main/java/org/apache/druid/segment/nested/VariantColumnSerializer.java","lineNumber":201,"sourceCode":"  public void open() throws IOException\n  {\n    if (!dictionarySerialized) {\n      throw new IllegalStateException(\"Dictionary not serialized, cannot open value serializer\");\n    }\n    intermediateValueWriter = new FixedIndexedIntWriter(segmentWriteOutMedium, false);\n    intermediateValueWriter.open();\n  }\n\n  @Override\n  public void serializeDictionaries(\n      Iterable<String> strings,\n      Iterable<Long> longs,\n      Iterable<Double> doubles,\n      Iterable<int[]> arrays\n  ) throws IOException\n  {\n    if (dictionarySerialized) {\n      throw new ISE(\"Value dictionaries already serialized for column [%s], cannot serialize again\", name);\n    }\n\n    // null is always 0\n    dictionaryWriter.write(null);\n    for (String value : strings) {\n      if (value == null) {\n        continue;\n      }\n\n      dictionaryWriter.write(value);\n    }\n\n    for (Long value : longs) {\n      if (value == null) {\n        continue;\n      }\n      longDictionaryWriter.write(value);\n    }","sourceCodeStart":183,"sourceCodeEnd":219,"githubUrl":"https://github.com/apache/druid/blob/9b90983fd291f26935af934383ce360473179e4d/processing/src/main/java/org/apache/druid/segment/nested/VariantColumnSerializer.java#L183-L219","documentation":"serializeDictionaries writes the null sentinel plus string/long/double/arrays dictionaries for a variant column and can only run once per serializer instance. If dictionarySerialized is already true, calling it again would corrupt the column, so it throws ISE 'Value dictionaries already serialized ... cannot serialize again'.","triggerScenarios":"Calling serializeDictionaries twice on the same VariantColumnSerializer, e.g. retry logic that re-invokes the method after a partial failure, or a merge path that processes dictionaries per-part and per-column.","commonSituations":"Custom segment merge tooling with retriable dictionary serialization; adding dictionary handling code to an existing merge pipeline without tracking state.","solutions":["Ensure serializeDictionaries is called exactly once per serializer instance","Use a fresh VariantColumnSerializer if dictionaries must be rewritten","Make retry wrappers idempotent or recreate the serializer on retry","Track serialization state in the calling merge code"],"exampleFix":"// before\nif (needsRetry) serializer.serializeDictionaries(...); // second call\n// after\nif (needsRetry) { serializer = createNewSerializer(name, medium); serializer.serializeDictionaries(...); }","handlingStrategy":"validation","validationCode":"if (serializer.isDictionarySerialized()) { throw new IllegalStateException(\"dictionaries already written for \" + name); }","typeGuard":null,"tryCatchPattern":"try { serializer.serializeDictionaries(strings, longs, doubles, arrays); } catch (ISE e) { if (e.getMessage().startsWith(\"Value dictionaries already serialized\")) { /* skip second call */ } else { throw e; } }","preventionTips":["Call serializeDictionaries exactly once per serializer","Make retry logic recreate the serializer instead of re-calling","Keep dictionary and value phases in one code path"],"tags":["druid","segment-writing","lifecycle"],"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"}