{"record":{"id":"90b6d787af5c6b0e","repo":"apache/seatunnel","slug":"recordkey-values-recordkey-for-fields-rec","errorCode":null,"errorMessage":"recordKey values: \"${recordKey}\" for fields: ${recordKeyFields} cannot be entirely null or empty.","messagePattern":"recordKey values: \"(.+?)\" for fields: (.+?) cannot be entirely null or empty\\.","errorType":"exception","errorClass":"HoodieKeyException","httpStatus":null,"severity":"error","filePath":"seatunnel-connectors-v2/connector-hudi/src/main/java/org/apache/seatunnel/connectors/seatunnel/hudi/sink/convert/HudiRecordConverter.java","lineNumber":116,"sourceCode":"                recordKey\n                        .append(recordKeyField)\n                        .append(\":\")\n                        .append(NULL_RECORD_KEY_PLACEHOLDER)\n                        .append(\",\");\n            } else if (recordKeyValue.isEmpty()) {\n                recordKey\n                        .append(recordKeyField)\n                        .append(\":\")\n                        .append(EMPTY_RECORD_KEY_PLACEHOLDER)\n                        .append(\",\");\n            } else {\n                recordKey.append(recordKeyField).append(\":\").append(recordKeyValue).append(\",\");\n                keyIsNullEmpty = false;\n            }\n        }\n        recordKey.deleteCharAt(recordKey.length() - 1);\n        if (keyIsNullEmpty) {\n            throw new HoodieKeyException(\n                    \"recordKey values: \\\"\"\n                            + recordKey\n                            + \"\\\" for fields: \"\n                            + hudiTableConfig.getRecordKeyFields()\n                            + \" cannot be entirely null or empty.\");\n        }\n        return recordKey.toString();\n    }\n\n    public String getRecordPartitionPath(\n            SeaTunnelRow element,\n            SeaTunnelRowType seaTunnelRowType,\n            HudiTableConfig hudiTableConfig) {\n        if (hudiTableConfig.getPartitionFields().isEmpty()) {\n            return \"\";\n        }\n\n        StringBuilder partitionPath = new StringBuilder();","sourceCodeStart":98,"sourceCodeEnd":134,"githubUrl":"https://github.com/apache/seatunnel/blob/cf67b549a7a6c35fa0beb12d83c62892427ea919/seatunnel-connectors-v2/connector-hudi/src/main/java/org/apache/seatunnel/connectors/seatunnel/hudi/sink/convert/HudiRecordConverter.java#L98-L134","documentation":"HudiRecordConverter.getRecordKey builds the Hudi record key by concatenating the values of the configured record key fields; if every field value is null or empty, it throws HoodieKeyException because a Hudi record must have a non-empty key for deduplication and indexing.","triggerScenarios":"Calling getRecordKey (via rowKey) on a SeaTunnelRow where all fields listed in the Hudi table's recordKeyFields configuration resolve to null or empty strings.","commonSituations":"Source data with null key columns (e.g. CDC rows with missing primary key); misconfigured recordKeyFields pointing at optional/nullable columns; upstream transforms dropping the key field.","solutions":["Configure recordKeyFields to point at non-nullable columns that are populated in the source data","Add an upstream transform (e.g. SQL/Filter) to drop or repair rows with null key fields before the Hudi sink","Set a Hudi precombine/key strategy or generate a default key (e.g. UUID) upstream when source rows lack a natural key","Verify field names in recordKeyFields match the actual SeaTunnel schema (typos yield null lookups)"],"exampleFix":"// before: recordKeyFields = \"user_id\" but rows have null user_id\n// after: coalesce upstream or use a generated key\nSQL transform: SELECT COALESCE(user_id, uuid()) AS user_id, ... FROM source","handlingStrategy":"validation","validationCode":"boolean allKeyFieldsNull = recordKeyFields.stream().allMatch(f -> row.getField(rowType.indexOf(f)) == null || \"\".equals(row.getField(rowType.indexOf(f))));\nif (allKeyFieldsNull) { throw new IllegalArgumentException(\"All record key fields are null; fix data or key config before writing to Hudi\"); }","typeGuard":"static boolean hasNonNullKey(SeaTunnelRow row, SeaTunnelRowType type, List<String> keyFields) {\n    return keyFields.stream().anyMatch(f -> {\n        int i = type.indexOf(f);\n        return i >= 0 && row.getField(i) != null && !String.valueOf(row.getField(i)).isEmpty();\n    });\n}","tryCatchPattern":null,"preventionTips":["Design recordKeyFields to reference NOT NULL primary-key columns","Validate a sample of source rows for null keys before job submission","Add a Filter transform to drop null-key rows explicitly"],"tags":["hudi","data-quality","null-key","sink"],"backgroundTag":"empty-required-field","analyzedSha":"cf67b549a7a6c35fa0beb12d83c62892427ea919","analyzedAt":"2026-09-10T21:44:55.265Z","contentChangedAt":"2026-09-10T21:44:55.265Z","schemaVersion":2},"datasetVersion":"2026-09-14T11:17:12.474Z"}