alibaba/canal · error · RuntimeException
rowKey值为空
Error message
rowKey值为空
What it means
HbaseSyncService.update() computes rowKeyBytes for each updated row; if it ends up null the method throws 'rowKey值为空'. null results when the rowKey column value is null/absent, or when typeConvert returns null for a null value (no composite rowKey, and the single rowKeyColumn value is null).
Source
Thrown at client-adapter/hbase/src/main/java/com/alibaba/otter/canal/client/adapter/hbase/service/HbaseSyncService.java:207
// 判断是否有复合主键修改
for (String updateColumn : old.get(index).keySet()) {
for (String rowKeyColumnName : rowKeyColumns) {
if (rowKeyColumnName.equalsIgnoreCase(updateColumn)) {
// 调用删除插入操作
deleteAndInsert(config, dml);
continue out;
}
}
}
String rowKeyVale = getRowKeys(rowKeyColumns, r);
rowKeyBytes = Bytes.toBytes(rowKeyVale);
} else if (rowKeyColumn == null) {
rowKeyBytes = typeConvert(null, hbaseMapping, r.values().iterator().next());
} else {
rowKeyBytes = getRowKeyBytes(hbaseMapping, rowKeyColumn, r);
}
if (rowKeyBytes == null) throw new RuntimeException("rowKey值为空");
Map<String, MappingConfig.ColumnItem> columnItems = hbaseMapping.getColumnItems();
HRow hRow = new HRow(rowKeyBytes);
for (String updateColumn : old.get(index).keySet()) {
if (hbaseMapping.getExcludeColumns() != null
&& hbaseMapping.getExcludeColumns().contains(updateColumn)) {
continue;
}
MappingConfig.ColumnItem columnItem = columnItems.get(updateColumn);
if (columnItem == null) {
String family = hbaseMapping.getFamily();
String qualifier = updateColumn;
if (hbaseMapping.isUppercaseQualifier()) {
qualifier = qualifier.toUpperCase();
}
Object newVal = r.get(updateColumn);
View on GitHub (pinned to 87be50e876)
Solutions
- Guarantee the rowKey column is non-null and unchanged-safe for UPDATEs; updates that change the rowKey are handled via deleteAndInsert, not update().
- Align the rowKey column name in the mapping with the DML column name exactly.
- Filter/cleanse null-PK updates upstream.
- If the PK genuinely changed, rely on the composite-rowKey path so deleteAndInsert is triggered.
Example fix
-- before: UPDATE sets rowKey col to NULL UPDATE t SET id = NULL WHERE x=1; -- after: keep rowKey non-null UPDATE t SET other = 1 WHERE id = 5;
Defensive patterns
Strategy: validation
Validate before calling
// Before update sync, verify the rowKey column is present and non-null
MappingConfig.HbaseMapping m = config.getHbaseMapping();
for (Map<String,Object> r : dml.getData()) {
String keyCol = m.getRowKey() != null
? m.getRowKey().split(",")[0].trim()
: m.getRowKeyColumn().getColumn();
if (r.get(keyCol) == null) throw new IllegalStateException("rowKey column " + keyCol + " is null in update data");
} Try / catch
try {
hbaseSyncService.sync(config, dml);
} catch (RuntimeException e) {
if (e.getMessage() != null && e.getMessage().contains("rowKey")) {
logger.error("UPDATE rowKey resolved null; check rowKey column name and null values");
}
throw e;
} Prevention
- Never update the single rowKey column to null (use composite rowKey + deleteAndInsert for key changes).
- Match rowKey column names exactly to DML column names.
- Filter null-PK update events upstream.
When it happens
Trigger: An UPDATE DML where the rowKey column (single or composite) value resolves to null in the new data; or the mapping's rowKey column name does not match the DML column so getRowKeyBytes/getRowKeys return null.
Common situations: Updating the rowKey column itself to null (canal routes to update() when a composite key column is NOT changed); source row whose PK is null; mismatched column name casing between mapping and DML.
Related errors
AI-assisted analysis of alibaba/canal@87be50e876 (2026-08-14).
Data as JSON: /api/errors/659ae09ca09c7654.
Report an issue: GitHub.