alibaba/canal · error · TableIdNotFoundException
not found tableId:{}
Error message
not found tableId:{} What it means
Thrown as TableIdNotFoundException when a RowsLogEvent arrives but event.getTable() returns null — meaning no TableMapLogEvent was seen for this tableId. The TableMapLogEvent is what maps a numeric tableId to schema/table/column metadata. Without it, Canal cannot interpret the row data.
Source
Thrown at parse/src/main/java/com/alibaba/otter/canal/parse/inbound/mysql/dbsync/LogEventConvert.java:458
private Entry parseRandLogEvent(RandLogEvent event) {
if (filterQueryDml) {
return null;
}
return buildQueryEntry(event.getQuery(), event.getHeader());
}
private Entry parseXidEvent(XidLogEvent event) {
TransactionEnd transactionEnd = createTransactionEnd(event.getXid());
Header header = createHeader(event.getHeader(), "", "", null);
return createEntry(header, EntryType.TRANSACTIONEND, transactionEnd.toByteString());
}
public TableMeta parseRowsEventForTableMeta(RowsLogEvent event) {
TableMapLogEvent table = event.getTable();
if (table == null) {
// tableId对应的记录不存在
throw new TableIdNotFoundException("not found tableId:" + event.getTableId());
}
boolean isHeartBeat = isAliSQLHeartBeat(table.getDbName(), table.getTableName());
boolean isRDSHeartBeat = tableMetaCache.isOnRDS() && isRDSHeartBeat(table.getDbName(), table.getTableName());
String fullname = table.getDbName() + "." + table.getTableName();
// check name filter
if (nameFilter != null && !nameFilter.filter(fullname)) {
return null;
}
if (nameBlackFilter != null && nameBlackFilter.filter(fullname)) {
return null;
}
// if (isHeartBeat || isRDSHeartBeat) {
// // 忽略rds模式的mysql.ha_health_check心跳数据
// return null;
// }View on GitHub (pinned to 87be50e876)
Solutions
- Ensure Canal starts from a transaction boundary (BEGIN event), not an arbitrary offset within a transaction.
- If the position is specified manually, adjust it to the start of the next complete transaction.
- Enable GTID-based positioning so Canal can correctly resume from transaction boundaries after restart.
- If the error is transient (only first event after restart), consider catching TableIdNotFoundException and letting Canal skip to the next transaction.
Example fix
# before — manual position in the middle of a transaction canal.instance.gtidenabled=false canal.instance.master.position=mysql-bin.000005:9876 # after — use GTID for safe transaction-boundary resumption canal.instance.gtidenabled=true canal.instance.gtid=3E4FA457-2A57-11E7-8F2A-1234567890AB:1-999999
Defensive patterns
Strategy: retry
Try / catch
try {
TableMeta meta = parseRowsEventForTableMeta(event);
} catch (TableIdNotFoundException e) {
// Missing TABLE_MAP event — likely started mid-transaction
// Skip this event and advance to the next transaction boundary
logger.warn("TableId {} not found, skipping event — likely mid-transaction start", event.getTableId(), e);
// Advance position to skip the incomplete transaction
} Prevention
- Use GTID-based positioning so Canal always resumes at transaction boundaries after restart.
- Avoid manually specifying binlog positions that point inside a transaction.
- When restarting Canal, let it auto-discover the position from zookeeper/meta mode rather than hardcoding.
When it happens
Trigger: parseRowsEventForTableMeta() is called on a RowsLogEvent whose TableMapLogEvent was not received. This occurs when Canal starts reading from a binlog position that is in the middle of a transaction (after the TABLE_MAP event but before the WRITE/UPDATE/DELETE_ROWS event), or when the TABLE_MAP event was on a previous binlog file that was rotated out of the in-memory map.
Common situations: Canal restarts and resumes from a position inside an incomplete transaction. The binlog rotation happened between TABLE_MAP and ROWS events. A very long transaction spans multiple binlog files and Canal reconnects mid-way. The starting position in instance.properties points to a row event offset rather than a transaction boundary.
Related errors
- No such method: '{}' @ {}
- No such field: '{}' @ {}
- Unable to unwrap {} to com.mysql.jdbc.ConnectionImpl
- Get null field:{}#io
- Unable to load com.mysql.jdbc.ConnectionImpl
AI-assisted analysis of alibaba/canal@87be50e876 (2026-08-14).
Data as JSON: /api/errors/963dfe8f3a88940a.
Report an issue: GitHub.