{"record":{"id":"f5a63ec71151bd0d","repo":"apache/beam","slug":"cannot-merge-two-types-fieldtype1-gettypename-and-fieldtype2","errorCode":null,"errorMessage":"Cannot merge two types: +fieldType1.getTypeName()+ and +fieldType2.getTypeName()","messagePattern":"Cannot merge two types: \\+fieldType1\\.getTypeName\\(\\)\\+ and \\+fieldType2\\.getTypeName\\(\\)","errorType":"validation","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"sdks/java/core/src/main/java/org/apache/beam/sdk/schemas/SchemaUtils.java","lineNumber":62,"sourceCode":"      throw new IllegalArgumentException(\n          \"Cannot merge schemas with different numbers of fields. \"\n              + \"schema1: \"\n              + schema1\n              + \" schema2: \"\n              + schema2);\n    }\n    Schema.Builder builder = Schema.builder();\n    for (int i = 0; i < schema1.getFieldCount(); ++i) {\n      String name = schema1.getField(i).getName();\n      builder.addField(\n          name, widenNullableTypes(schema1.getField(i).getType(), schema2.getField(i).getType()));\n    }\n    return builder.build();\n  }\n\n  static FieldType widenNullableTypes(FieldType fieldType1, FieldType fieldType2) {\n    if (fieldType1.getTypeName() != fieldType2.getTypeName()) {\n      throw new IllegalArgumentException(\n          \"Cannot merge two types: \"\n              + fieldType1.getTypeName()\n              + \" and \"\n              + fieldType2.getTypeName());\n    }\n\n    FieldType result;\n    switch (fieldType1.getTypeName()) {\n      case ROW:\n        result =\n            FieldType.row(\n                mergeWideningNullable(fieldType1.getRowSchema(), fieldType2.getRowSchema()));\n        break;\n      case ARRAY:\n        FieldType arrayElementType =\n            widenNullableTypes(\n                fieldType1.getCollectionElementType(), fieldType2.getCollectionElementType());\n        result = FieldType.array(arrayElementType);","sourceCodeStart":44,"sourceCodeEnd":80,"githubUrl":"https://github.com/apache/beam/blob/12126d8942aaf848030c478b4c6a28c6af861c66/sdks/java/core/src/main/java/org/apache/beam/sdk/schemas/SchemaUtils.java#L44-L80","documentation":"widenNullableTypes computes the widened (nullable-if-either) FieldType for two field types and requires both to share the same TypeName (e.g. both STRING, both INT64). If the TypeNames differ it throws IllegalArgumentException. It is used by mergeWideningNullable and collection/key/value type merging, so any schema merge of mismatched field types hits this.","triggerScenarios":"Merging two schemas where the same-position fields have different TypeName values — e.g. schema1 field 'id' is INT64 while schema2's 'id' is STRING; also nested merges of array element types, iterable element types, or map key/value types with differing TypeNames.","commonSituations":"Upstream type change (column switched from int to string); one schema generated from Avro and the other from Java types with different mappings; versioned pipelines where a field's type was refactored between releases.","solutions":["Align the field types at each position so TypeNames match; convert the data (e.g. cast INT64 to STRING) before merging.","Build a new schema explicitly with Schema.builder() mapping types to the desired target type instead of widening.","Regenerate both schemas from the same, current class/Avro definition.","Catch IllegalArgumentException and compare fieldType.getTypeName() per field to find the first mismatch."],"exampleFix":"// before\nSchema merged = SchemaUtils.mergeWideningNullable(schemaIntId, schemaStringId); // throws\n// after\nSchema fixed = Schema.builder()\n    .addStringField(\"id\") // convert int-typed data to string first\n    .build();\nSchema merged = SchemaUtils.mergeWideningNullable(fixed, schemaStringId);","handlingStrategy":"validation","validationCode":"boolean typesMatch = IntStream.range(0, Math.min(s1.getFieldCount(), s2.getFieldCount()))\n    .allMatch(i -> s1.getField(i).getType().getTypeName()\n        == s2.getField(i).getType().getTypeName());\nif (typesMatch) {\n  Schema merged = SchemaUtils.mergeWideningNullable(s1, s2);\n}","typeGuard":"boolean sameTypeNameAt(Schema s1, Schema s2, int i) {\n  return s1.getField(i).getType().getTypeName()\n      == s2.getField(i).getType().getTypeName();\n}","tryCatchPattern":"try {\n  Schema merged = SchemaUtils.mergeWideningNullable(s1, s2);\n} catch (IllegalArgumentException e) {\n  LOG.error(\"FieldType TypeName mismatch: {}\", e.getMessage());\n  throw new SchemaMergeException(e);\n}","preventionTips":["Keep a single schema definition (class/Avro) as the source of truth for both sides.","Convert field types explicitly before merging rather than relying on widening.","Pin Beam versions across pipeline stages so generated types don't drift."],"tags":["java","beam","schema","type-mismatch"],"backgroundTag":"type-mismatch","analyzedSha":"12126d8942aaf848030c478b4c6a28c6af861c66","analyzedAt":"2026-09-13T01:50:10.254Z","contentChangedAt":"2026-09-13T01:50:10.254Z","schemaVersion":2},"datasetVersion":"2026-09-14T16:17:12.679Z"}