{"record":{"id":"b51cffd33a5ed962","repo":"apache/druid","slug":"dim-s-types-not-equal-expected-d-found-d","errorCode":null,"errorMessage":"Dim [%s] types not equal. Expected %d found %d","messagePattern":"Dim \\[(.+?)\\] types not equal\\. Expected (.+?) found (.+?)","errorType":"validation","errorClass":"SegmentValidationException","httpStatus":null,"severity":"error","filePath":"processing/src/main/java/org/apache/druid/segment/IndexIO.java","lineNumber":272,"sourceCode":"    }\n    final List<Object> dims1 = rp1.getDimensionValuesForDebug();\n    final List<Object> dims2 = rp2.getDimensionValuesForDebug();\n    if (dims1.size() != dims2.size()) {\n      throw new SegmentValidationException(\"Dim lengths not equal %s vs %s\", dims1, dims2);\n    }\n    final List<String> dim1Names = adapter1.getDimensionNames(false);\n    final List<String> dim2Names = adapter2.getDimensionNames(false);\n    int dimCount = dims1.size();\n    for (int i = 0; i < dimCount; ++i) {\n      final String dim1Name = dim1Names.get(i);\n      final String dim2Name = dim2Names.get(i);\n\n      ColumnCapabilities capabilities1 = adapter1.getCapabilities(dim1Name);\n      ColumnCapabilities capabilities2 = adapter2.getCapabilities(dim2Name);\n      ColumnType dim1Type = capabilities1.toColumnType();\n      ColumnType dim2Type = capabilities2.toColumnType();\n      if (!Objects.equals(dim1Type, dim2Type)) {\n        throw new SegmentValidationException(\n            \"Dim [%s] types not equal. Expected %d found %d\",\n            dim1Name,\n            dim1Type,\n            dim2Type\n        );\n      }\n\n      Object vals1 = dims1.get(i);\n      Object vals2 = dims2.get(i);\n      if (isNullRow(vals1) ^ isNullRow(vals2)) {\n        throw notEqualValidationException(dim1Name, vals1, vals2);\n      }\n      boolean vals1IsList = vals1 instanceof List;\n      boolean vals2IsList = vals2 instanceof List;\n      if (vals1IsList ^ vals2IsList) {\n        if (vals1IsList) {\n          if (((List) vals1).size() != 1 || !Objects.equals(((List) vals1).get(0), vals2)) {\n            throw notEqualValidationException(dim1Name, vals1, vals2);","sourceCodeStart":254,"sourceCodeEnd":290,"githubUrl":"https://github.com/apache/druid/blob/9b90983fd291f26935af934383ce360473179e4d/processing/src/main/java/org/apache/druid/segment/IndexIO.java#L254-L290","documentation":"validateRowValues compares column capabilities of each dimension pair across the two segments. The message text mistakenly formats ColumnType objects with %d, but the failure means the two segments declare different column types (e.g. STRING vs LONG) for the same dimension. Such segments are not equivalent and validation aborts.","triggerScenarios":"IndexIO.validateTwoSegments on segments where adapter.getCapabilities(dimName).toColumnType() differs for a shared dimension — one segment auto-typed a dimension as numeric while the other kept it as string.","commonSituations":"Re-ingestion with different auto-detection results (numbers parsed as strings in one run); schema drift after changing ingest spec dimension type declarations; validating segments from different Druid versions with different typing rules.","solutions":["Fix the ingestion spec to declare the same explicit dimension type for both segments and re-ingest","Re-persist one segment with dimension conversion (IndexMerger convert) to match the other's column type","Verify with SegmentMetadataQuery which column types differ before validating"],"exampleFix":"// before (ingest spec, inconsistent typing)\n\"dimensions\": [\"page\"]\n// after\n\"dimensions\": [{\"type\": \"string\", \"name\": \"page\"}]\n// keep identical declarations in both ingestion specs","handlingStrategy":"validation","validationCode":"for (String dim : dims) {\n  ColumnType t1 = adapter1.getCapabilities(dim).toColumnType();\n  ColumnType t2 = adapter2.getCapabilities(dim).toColumnType();\n  if (!Objects.equals(t1, t2)) {\n    throw new IllegalStateException(\"Type mismatch on dim \" + dim + \": \" + t1 + \" vs \" + t2);\n  }\n}","typeGuard":null,"tryCatchPattern":"try {\n  IndexIO.validateTwoSegments(adapter1, adapter2);\n} catch (SegmentValidationException e) {\n  if (e.getMessage().contains(\"types not equal\")) {\n    // convert one segment's column type before retrying\n  }\n}","preventionTips":["Declare explicit dimension types in ingestion specs to avoid auto-detection drift","Compare column capabilities with a SegmentMetadataQuery before merging/validating"],"tags":["druid","segment","validation","column-type"],"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"}