vitessio/vitess · error
unknown tableID %v in WriteRows event
Error message
unknown tableID %v in WriteRows event
What it means
A WriteRowsEvent carries rows identified only by a numeric table_id that must have been declared by a preceding TABLE_MAP_EVENT. If tableMaps has no entry for that ID, the streamer cannot identify the table and aborts the stream.
Source
Thrown at go/vt/binlog/binlog_streamer.go:521
if bls.extractPK {
tce.pkNames = make([]*querypb.Field, len(tce.ti.PKColumns))
tce.pkIndexes = make([]int, len(tce.ti.Fields))
for i := range tce.pkIndexes {
// Put -1 as default in here.
tce.pkIndexes[i] = -1
}
for i, c := range tce.ti.PKColumns {
// Patch in every PK column index.
tce.pkIndexes[c] = i
// Fill in pknames
tce.pkNames[i] = tce.ti.Fields[c]
}
}
case ev.IsWriteRows():
tableID := ev.TableID(format)
tce, ok := tableMaps[tableID]
if !ok {
return pos, fmt.Errorf("unknown tableID %v in WriteRows event", tableID)
}
if tce.ti == nil {
// Skip cross-db statements.
continue
}
setTimestamp := &binlogdatapb.BinlogTransaction_Statement{
Category: binlogdatapb.BinlogTransaction_Statement_BL_SET,
Sql: fmt.Appendf(nil, "SET TIMESTAMP=%d", ev.Timestamp()),
}
statements = append(statements, FullBinlogStatement{
Statement: setTimestamp,
})
rows, err := ev.Rows(format, tce.tm)
if err != nil {
return pos, err
}
View on GitHub (pinned to 01a25a7d17)
Solutions
- Restart the stream from a clean transaction boundary (a GTID/position before the transaction) so TABLE_MAP and rows events stay paired
- Validate the binlog file with mysqlbinlog to find corruption or missing table-map events
- If filtering databases, ensure filtering never drops TABLE_MAP events whose rows events are still streamed
- Fix custom event generators to emit TABLE_MAP before rows events
Defensive patterns
Strategy: validation
Validate before calling
// ensure stream starts at a transaction boundary: // mysqlbinlog --start-position=<pos> <file> | head -50 // confirm a Table_map event precedes the Write_rows event
Try / catch
err := streamer.Stream(ctx, signals)
if err != nil && strings.Contains(err.Error(), "unknown tableID") {
// restart from a clean GTID/transaction boundary
} Prevention
- Start streams at transaction boundaries, not mid-transaction
- Never filter TABLE_MAP events out of row-based streams
- Validate binlog files with mysqlbinlog
- Avoid manual edits to binlog/relay files
When it happens
Trigger: In parseEvents, ev.IsWriteRows() yields a tableID not present in the tableMaps built from prior TABLE_MAP events — the map event was skipped (wrong db filter), lost, or the rows event is corrupt/misaligned.
Common situations: Stream started mid-transaction so the TABLE_MAP was missed; binlog file corruption causing event misalignment; custom binlog emitters writing rows without a matching table map; cross-database replication where the map event was filtered out.
Related errors
- unknown tableID %v in UpdateRows event
- unknown tableID %v in DeleteRows event
- unknown table %v in schema
- [%v] cached columns count[%d] mismatch binglog row [%d]
- GetPreviousGTIDs: previous GTIDs not found
AI-assisted analysis of vitessio/vitess@01a25a7d17 (2026-09-01).
Data as JSON: /api/errors/7c73825d9dedb07f.
Report an issue: GitHub.