{"record":{"id":"88816a6895657d4a","repo":"apache/iceberg","slug":"invalid-primary-key-s-column-s-is-nullable","errorCode":null,"errorMessage":"Invalid primary key '%s'. Column '%s' is nullable.","messagePattern":"Invalid primary key '(.+?)'\\. Column '(.+?)' is nullable\\.","errorType":"validation","errorClass":"org.apache.flink.table.api.ValidationException","httpStatus":null,"severity":"error","filePath":"flink/v1.20/flink/src/main/java/org/apache/iceberg/flink/FlinkSchemaUtil.java","lineNumber":373,"sourceCode":"    for (String columnName : primaryKey.getColumns()) {\n      Column column = columnsByNameLookup.get(columnName);\n      if (column == null) {\n        throw new ValidationException(\n            String.format(\n                \"Invalid primary key '%s'. Column '%s' does not exist.\",\n                primaryKey.getName(), columnName));\n      }\n\n      if (!column.isPhysical()) {\n        throw new ValidationException(\n            String.format(\n                \"Invalid primary key '%s'. Column '%s' is not a physical column.\",\n                primaryKey.getName(), columnName));\n      }\n\n      final LogicalType columnType = column.getDataType().getLogicalType();\n      if (columnType.isNullable()) {\n        throw new ValidationException(\n            String.format(\n                \"Invalid primary key '%s'. Column '%s' is nullable.\",\n                primaryKey.getName(), columnName));\n      }\n    }\n  }\n}\n","sourceCodeStart":355,"sourceCodeEnd":381,"githubUrl":"https://github.com/apache/iceberg/blob/86d9c8fc543e7c56c9f624eb725f76c9baff9570/flink/v1.20/flink/src/main/java/org/apache/iceberg/flink/FlinkSchemaUtil.java#L355-L381","documentation":"Primary key columns must be NOT NULL in Flink; validatePrimaryKey rejects any key column whose LogicalType is nullable. This matches Iceberg's identifier-field requirements, which demand non-null key columns.","triggerScenarios":"Defining PRIMARY KEY on a column declared without NOT NULL in Flink DDL (Flink makes declared key columns non-null automatically only when declared together in some paths; programmatic constraints can bypass this), or building a ResolvedSchema where key columns retain nullable types.","commonSituations":"Constructing UniqueConstraint + ResolvedSchema in code without marking key columns non-null; DDL where the key column was added without NOT NULL; schema conversions from systems allowing nullable keys.","solutions":["Declare key columns with NOT NULL in the DDL, e.g. PRIMARY KEY (id) NOT ENFORCED with id NOT NULL.","When building schemas programmatically, use the non-nullable LogicalType (e.g. DataTypes.BIGINT().NOT_NULL()) for key columns.","Use ResolvedSchema.newTableSchema-style helpers that enforce key nullability."],"exampleFix":"// before\nid BIGINT, PRIMARY KEY (id) NOT ENFORCED\n// after\nid BIGINT NOT NULL, PRIMARY KEY (id) NOT ENFORCED","handlingStrategy":"validation","validationCode":"for (String col : primaryKey.getColumns()) {\n  if (schema.getColumn(col) != null &&\n      schema.getColumn(col).getDataType().getLogicalType().isNullable()) {\n    throw new IllegalArgumentException(\"PK column must be NOT NULL: \" + col);\n  }\n}","typeGuard":"null","tryCatchPattern":"try {\n  FlinkSchemaUtil.toResolvedSchema(schema, partitionKeys, primaryKey);\n} catch (ValidationException e) {\n  LOG.error(\"PK column nullable: {}\", e.getMessage());\n  throw e;\n}","preventionTips":["Always declare key columns NOT NULL in DDL and DataTypes....NOT_NULL() in code.","Remember Flink auto-marks declared PK columns NOT NULL only in DDL; programmatic schemas need explicit types.","Add a schema lint step validating key nullability before job submission."],"tags":["flink","schema","primary-key"],"backgroundTag":"schema-validation-failed","analyzedSha":"86d9c8fc543e7c56c9f624eb725f76c9baff9570","analyzedAt":"2026-09-12T00:46:39.097Z","contentChangedAt":"2026-09-12T00:46:39.097Z","schemaVersion":2},"datasetVersion":"2026-09-14T16:17:12.679Z"}