{"record":{"id":"d7d73f2147ba869e","repo":"apache/beam","slug":"conflicting-field-modes-for-field-s-s-vs-s","errorCode":null,"errorMessage":"Conflicting field modes for field '%s': %s vs %s","messagePattern":"Conflicting field modes for field '(.+?)': (.+?) vs (.+?)","errorType":"exception","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"sdks/java/io/google-cloud-platform/src/main/java/org/apache/beam/sdk/io/gcp/bigquery/UpgradeTableSchema.java","lineNumber":234,"sourceCode":"    TableFieldSchema.Mode mode1 =\n        f1.getMode() == TableFieldSchema.Mode.MODE_UNSPECIFIED\n            ? TableFieldSchema.Mode.NULLABLE\n            : f1.getMode();\n    TableFieldSchema.Mode mode2 =\n        f2.getMode() == TableFieldSchema.Mode.MODE_UNSPECIFIED\n            ? TableFieldSchema.Mode.NULLABLE\n            : f2.getMode();\n\n    boolean isNull =\n        ((mode1 == TableFieldSchema.Mode.NULLABLE) && (mode2 != TableFieldSchema.Mode.REPEATED))\n            || (mode2 == TableFieldSchema.Mode.NULLABLE && mode1 != TableFieldSchema.Mode.REPEATED);\n    if (isNull) {\n      builder.setMode(TableFieldSchema.Mode.NULLABLE);\n    } else if (mode1.equals(mode2)) {\n      // Either merging REPEATED with REPEATED or REQUIRED with REQUIRED.\n      builder.setMode(mode1);\n    } else {\n      throw new IllegalArgumentException(\n          String.format(\n              \"Conflicting field modes for field '%s': %s vs %s\",\n              f1.getName(), f1.getMode(), f2.getMode()));\n    }\n\n    // Recursively merge nested fields if the type is STRUCT (Record)\n    if (f1.getType() == TableFieldSchema.Type.STRUCT) {\n      builder.addAllFields(mergeFields(f1.getFieldsList(), f2.getFieldsList()));\n    }\n\n    return builder.build();\n  }\n\n  public static boolean isPayloadSchemaOutOfDate(\n      StorageApiWritePayload payload,\n      ThrowingSupplier<byte[]> schemaHash,\n      ThrowingSupplier<Descriptors.Descriptor> schemaDescriptor)\n      throws Exception {","sourceCodeStart":216,"sourceCodeEnd":252,"githubUrl":"https://github.com/apache/beam/blob/12126d8942aaf848030c478b4c6a28c6af861c66/sdks/java/io/google-cloud-platform/src/main/java/org/apache/beam/sdk/io/gcp/bigquery/UpgradeTableSchema.java#L216-L252","documentation":"mergeField also reconciles the MODE of a field (NULLABLE, REQUIRED, REPEATED). NULLABLE can be merged with anything (the result becomes NULLABLE), and identical modes merge to themselves, but two different non-null modes (e.g. REQUIRED vs REPEATED) are irreconcilable, so the library throws this IllegalArgumentException.","triggerScenarios":"Merging two schema versions where the same field has f1.getMode() != f2.getMode() and neither is NULLABLE, e.g. REQUIRED in one and REPEATED in the other.","commonSituations":"A column changed from REQUIRED to REPEATED (or vice versa) between schema revisions; codegen emitted different mode defaults; manually edited table definitions disagree on mode.","solutions":["Make the field's mode consistent across both schema definitions (choose the correct mode in your source schema).","If one side should tolerate absence, set the mode to NULLABLE in one of the definitions — NULLABLE merges with any mode.","If a REQUIRED field really became REPEATED, migrate the data/model so both schemas describe the same cardinality."],"exampleFix":"// before\nTableFieldSchema f1 = new TableFieldSchema().setName(\"tags\").setMode(\"REQUIRED\");\nTableFieldSchema f2 = new TableFieldSchema().setName(\"tags\").setMode(\"REPEATED\");\n// after\nTableFieldSchema f1 = new TableFieldSchema().setName(\"tags\").setMode(\"REPEATED\");\nTableFieldSchema f2 = new TableFieldSchema().setName(\"tags\").setMode(\"REPEATED\");","handlingStrategy":"validation","validationCode":"if (!Objects.equals(f1.getMode(), f2.getMode())\n    && !TableFieldSchema.Mode.NULLABLE.equals(f1.getMode())\n    && !TableFieldSchema.Mode.NULLABLE.equals(f2.getMode())) {\n  throw new IllegalArgumentException(\"Mode conflict on field \" + f1.getName());\n}","typeGuard":null,"tryCatchPattern":"try { merged = mergeFields(f1, f2); } catch (IllegalArgumentException e) { log.warn(\"Mode conflict, treating as NULLABLE: {}\", e.getMessage()); return f1.toBuilder().setMode(NULLABLE).build(); }","preventionTips":["Default new fields to NULLABLE so they merge with any mode.","Never change REQUIRED to REPEATED in place — add a new field instead.","Codify mode rules in schema CI checks."],"tags":["bigquery","schema","mode-conflict"],"backgroundTag":"schema-validation-failed","analyzedSha":"12126d8942aaf848030c478b4c6a28c6af861c66","analyzedAt":"2026-09-13T01:50:10.254Z","contentChangedAt":"2026-09-13T01:50:10.254Z","schemaVersion":2},"datasetVersion":"2026-09-20T03:17:13.778Z"}