{"record":{"id":"395b9f40a50d6bbf","repo":"apache/seatunnel","slug":"primary-key-is-nullable-for-catalog-table","errorCode":null,"errorMessage":"Primary key({}) is nullable for catalog table {}","messagePattern":"Primary key\\((.+?)\\) is nullable for catalog table (.+?)","errorType":"console","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"seatunnel-connectors-v2/connector-cdc/connector-cdc-base/src/main/java/org/apache/seatunnel/connectors/cdc/base/utils/CatalogTableUtils.java","lineNumber":92,"sourceCode":"        for (String pk : config.getPrimaryKeys()) {\n            if (!columnNames.contains(pk)) {\n                throw new IllegalArgumentException(\n                        String.format(\n                                \"Primary key(%s) is not in table(%s) columns(%s)\",\n                                pk, table.getTablePath(), columnNames));\n            }\n        }\n        PrimaryKey primaryKeys =\n                PrimaryKey.of(\n                        \"pk\" + (config.getPrimaryKeys().hashCode() & Integer.MAX_VALUE),\n                        config.getPrimaryKeys());\n        List<Column> columns =\n                table.getTableSchema().getColumns().stream()\n                        .map(\n                                column -> {\n                                    if (config.getPrimaryKeys().contains(column.getName())\n                                            && column.isNullable()) {\n                                        log.warn(\n                                                \"Primary key({}) is nullable for catalog table {}\",\n                                                column.getName(),\n                                                table.getTablePath());\n                                        return PhysicalColumn.of(\n                                                column.getName(),\n                                                column.getDataType(),\n                                                column.getColumnLength(),\n                                                false,\n                                                column.getDefaultValue(),\n                                                column.getComment());\n                                    }\n                                    return column;\n                                })\n                        .collect(Collectors.toList());\n\n        return CatalogTable.of(\n                table.getTableId(),\n                TableSchema.builder()","sourceCodeStart":74,"sourceCodeEnd":110,"githubUrl":"https://github.com/apache/seatunnel/blob/cf67b549a7a6c35fa0beb12d83c62892427ea919/seatunnel-connectors-v2/connector-cdc/connector-cdc-base/src/main/java/org/apache/seatunnel/connectors/cdc/base/utils/CatalogTableUtils.java#L74-L110","documentation":"CatalogTableUtils.mergeCatalogTableConfig overrides CDC table columns: when a configured primary key column is nullable in the discovered catalog table schema, it is replaced with a non-nullable PhysicalColumn and this warning is logged. Sink primary keys must be non-nullable; a nullable primary key would break upsert/key-based writes.","triggerScenarios":"A catalog table config declares primary keys that are nullable columns in the source schema (e.g. a unique-but-nullable index used as PK, or discovered schema marking PK columns nullable).","commonSituations":"Sources like MySQL where the discovered schema misreports nullability; users choosing secondary/nullable unique keys as primary-keys; views or tables without true primary keys.","solutions":["Choose a truly non-nullable column (or column set) as the primary key in the config.","Alter the source table so the primary key column is NOT NULL.","If the source genuinely has no usable primary key, configure the connector's debezium primary key handling or use a different key strategy.","Verify the effective schema after merge; the util already coerces nullability, so this warning mainly flags a risky key choice."],"exampleFix":"// before\ncatalog-tables = [{ table = \"mydb.events\", primary-keys = [\"optional_col\"] }] // nullable\n// after: pick a non-nullable key\ncatalog-tables = [{ table = \"mydb.events\", primary-keys = [\"id\"] }]","handlingStrategy":"validation","validationCode":"// ensure configured primary keys are non-nullable in source schema\nfor (String pk : config.getPrimaryKeys()) {\n  Column c = schema.getColumn(pk);\n  if (c != null && c.isNullable()) throw new IllegalArgumentException(\"nullable PK: \" + pk);\n}","typeGuard":"if (column.isNullable() && config.getPrimaryKeys().contains(column.getName())) coerceToNonNull(column);","tryCatchPattern":"// warning-only coercion; choose valid keys instead","preventionTips":["Verify PK columns are NOT NULL on the source","Prefer true primary keys over nullable unique indexes","Check discovered schema nullability on first run","Add NOT NULL constraints upstream if keys must be used"],"tags":["cdc","primary-key","schema","nullable"],"backgroundTag":"schema-validation-failed","analyzedSha":"cf67b549a7a6c35fa0beb12d83c62892427ea919","analyzedAt":"2026-09-10T21:44:55.265Z","contentChangedAt":"2026-09-10T21:44:55.265Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}