apache/druid · error · ISE

Cannot merge columns of type

Error message

Cannot merge columns of type[%s] and format[%s] and with [%s] and [%s]

What it means

StringDictionaryEncodedColumnFormat.merge() falls through to this ISE when the other format is neither a CapabilitiesBasedFormat nor a compatible mergeable format — i.e. two string-typed formats whose concrete format classes cannot be merged (for example legacy formats or unknown format implementations mixed in one merge job). Raised via combine/aggregate during segment merging.

Solutions

  1. Reindex/compact the segments to a single common format before merging (druid.compaction.* or re-index task)
  2. Ensure all nodes in the merge path run compatible Druid versions
  3. Check for custom ColumnFormat implementations that don't support merge and implement merge() for them

Example fix

// before
// merging segments with legacy string column format and new dictionary-encoded format directly
// after
// run a re-index task to normalize formats first:
// ioConfig: { "type": "index_parallel", "inputSource": { "type": "druid", "dataSource": "src", "interval": "..." } }
// which rewrites all segments to the current dictionary-encoded format before merging
Defensive patterns

Strategy: validation

Validate before calling

if (!(otherFormat instanceof CapabilitiesBasedFormat) && !otherFormat.getClass().equals(this.getClass())) {
  throw new IllegalStateException("Incompatible column formats for merge: " + otherFormat.getClass().getName());
}

Type guard

boolean isMergeableWith(ColumnFormat self, ColumnFormat other) {
  return other instanceof CapabilitiesBasedFormat || other.getClass().equals(self.getClass());
}

Try / catch

try {
  ColumnFormat merged = self.merge(otherFormat, caps);
} catch (ISE e) {
  // fall back to re-indexing the segments into a common format
  submitReindexTask(segments);
}

Prevention

When it happens

Trigger: Calling merge() with an otherFormat that is not a CapabilitiesBasedFormat and not mergeable with this StringDictionaryEncodedColumnFormat implementation — e.g. a custom/foreign ColumnFormatSpec or a legacy format class in the same merge.

Common situations: Compaction/merge jobs spanning segments written by different Druid versions or different format specifications (e.g. one with dictionary encoding version X, another with an incompatible or custom format); rolling upgrades with mixed segment format versions.

Understand the failure class

Background: "is not a compatible type" / "cannot merge" errors: when a value's type doesn't match what the library requires — this error's family across 65 libraries.

Related errors


AI-assisted analysis of apache/druid@9b90983fd2 (2026-09-07). Data as JSON: /api/errors/9c6da1f3b699433a. Report an issue: GitHub.

Appendix: source

Thrown at processing/src/main/java/org/apache/druid/segment/column/StringDictionaryEncodedColumnFormat.java:142

      if (!otherCaps.is(ValueType.STRING)) {
        throw new ISE(
            "Cannot merge columns of type[%s] and format[%s] with type[%s] and format[%s]",
            ColumnType.STRING,
            this.getClass().getName(),
            otherFormat.getLogicalType(),
            otherFormat.getClass().getName()
        );
      }
      return new StringDictionaryEncodedColumnFormat(
          hasMultipleValues || otherCaps.hasMultipleValues().isMaybeTrue(),
          hasNulls || otherCaps.hasNulls().isMaybeTrue(),
          hasBitmapIndexes && otherCaps.hasBitmapIndexes(),
          hasSpatialIndexes || otherCaps.hasSpatialIndexes(),
          columnFormatSpec
      );
    }

    throw new ISE(
        "Cannot merge columns of type[%s] and format[%s] and with [%s] and [%s]",
        ColumnType.STRING,
        this.getClass().getName(),
        otherFormat.getLogicalType(),
        otherFormat.getClass().getName()
    );
  }
}

View on GitHub (pinned to 9b90983fd2)