{"record":{"id":"b1fcae5ff0027899","repo":"apache/druid","slug":"cannot-merge-columns-of-type-s-and-format-s-an-b1fcae","errorCode":null,"errorMessage":"Cannot merge columns of type[%s] and format[%s] and with [%s] and [%s]","messagePattern":"Cannot merge columns of type\\[(.+?)\\] and format\\[(.+?)\\] and with \\[(.+?)\\] and \\[(.+?)\\]","errorType":"exception","errorClass":"IllegalStateException","httpStatus":null,"severity":"error","filePath":"processing/src/main/java/org/apache/druid/segment/nested/NestedCommonFormatColumn.java","lineNumber":152,"sourceCode":"        final Format other = (Format) otherFormat;\n        // when merging formats in the same ingestion job, all segments should have the exact same columnFormatSpec, so\n        // no need to merge that\n        if (!logicalType.equals(other.logicalType)) {\n          return new Format(\n              ColumnType.leastRestrictiveType(logicalType, other.logicalType),\n              hasNulls || other.hasNulls,\n              false,\n              columnFormatSpec\n          );\n        }\n        return new Format(\n            logicalType,\n            hasNulls || other.hasNulls,\n            enforceLogicalType || other.enforceLogicalType,\n            columnFormatSpec\n        );\n      }\n      throw new ISE(\n          \"Cannot merge columns of type[%s] and format[%s] and with [%s] and [%s]\",\n          logicalType,\n          this.getClass().getName(),\n          otherFormat.getLogicalType(),\n          otherFormat.getClass().getName()\n      );\n    }\n\n    @Override\n    public ColumnCapabilities toColumnCapabilities()\n    {\n      if (logicalType.isPrimitive() || logicalType.isArray()) {\n        return ColumnCapabilitiesImpl.createDefault()\n                                     .setType(logicalType)\n                                     .setDictionaryEncoded(true)\n                                     .setDictionaryValuesSorted(true)\n                                     .setDictionaryValuesUnique(true)\n                                     .setHasBitmapIndexes(true)","sourceCodeStart":134,"sourceCodeEnd":170,"githubUrl":"https://github.com/apache/druid/blob/9b90983fd291f26935af934383ce360473179e4d/processing/src/main/java/org/apache/druid/segment/nested/NestedCommonFormatColumn.java#L134-L170","documentation":"NestedCommonFormatColumn.merge() merges two shared dictionary/format definitions during nested-column serialization. It only succeeds when both sides have the same logical type and compatible format implementation classes; otherwise it throws an ISE because there is no defined way to combine the two column formats.","triggerScenarios":"Writing/merging nested columns where two columns (or two parts of the same column) resolve to different logical types (e.g. LONG vs STRING) or different NestedCommonFormatColumn implementation classes.","commonSituations":"Schema drift during ingestion where the same field is sometimes a string and sometimes a number with incompatible coercions; merging partial dictionary state in compaction or task replication; mixing segment versions/formats.","solutions":["Ensure the field's logical type is consistent across all input rows (use SQL CAST or an ingestion transform to normalize the type).","Check ingestion spec for functions producing divergent types (e.g. expressions returning both string and numeric).","Re-run the ingestion/compaction so both sides serialize with the same format version and implementation.","Verify all tasks in a distributed ingestion run the same Druid version and identical column format configuration."],"exampleFix":"// before: expression yields mixed types\n// expr: \"concat(\\\"x\\\", n)\" sometimes STRING, sometimes LONG input\n// after: force a single logical type in the ingestion spec\n// \"type\": \"long\",\n// \"expr\": \"CAST(n AS LONG)\"","handlingStrategy":"validation","validationCode":"// ensure consistent logical type across inputs before merging/ingesting\nif (!Objects.equals(thisFormat.getLogicalType(), otherFormat.getLogicalType())) {\n  throw new IllegalArgumentException(\"Normalize field type before merge\");\n}","typeGuard":"boolean mergeable(NestedCommonFormatColumn a, NestedCommonFormatColumn b) {\n  return a.getClass().equals(b.getClass()) &&\n      Objects.equals(a.getLogicalType(), b.getLogicalType());\n}","tryCatchPattern":"try {\n  merged = format.merge(other);\n} catch (IllegalStateException e) {\n  if (e.getMessage().startsWith(\"Cannot merge columns of type\")) {\n    log.error(e, \"Type/format mismatch while merging nested column\");\n  } else throw e;\n}","preventionTips":["Normalize field types with CAST/transforms in the ingestion spec","Run identical Druid versions and ingestion specs on all tasks","Watch for schema drift on fields that mix strings and numbers"],"tags":["druid","nested-column","merge","type-mismatch"],"backgroundTag":"type-mismatch","analyzedSha":"9b90983fd291f26935af934383ce360473179e4d","analyzedAt":"2026-09-07T13:32:30.957Z","contentChangedAt":"2026-09-07T13:32:30.957Z","schemaVersion":2},"datasetVersion":"2026-09-14T11:17:12.474Z"}