vitessio/vitess · error
metadataRead: unhandled data type: %v
Error message
metadataRead: unhandled data type: %v
What it means
metadataWrite serializes a column's optional metadata and panics with a vterrors INTERNAL error (note: the message text says "metadataRead" but it is raised from metadataWrite) when the column type is not in its supported switch. The default branch exists for tests with unknown types only.
Source
Thrown at go/mysql/binlog_event_rbr.go:219
// One byte.
data[pos] = byte(value)
return pos + 1
case binlog.TypeNewDecimal, binlog.TypeEnum, binlog.TypeSet, binlog.TypeString:
// Two bytes, Big Endian because of crazy encoding.
data[pos] = byte(value >> 8)
data[pos+1] = byte(value)
return pos + 2
case binlog.TypeVarchar, binlog.TypeBit, binlog.TypeVarString:
// Two bytes, Little Endian
data[pos] = byte(value)
data[pos+1] = byte(value >> 8)
return pos + 2
default:
// Unknown type. This is used in tests only, so panic.
panic(vterrors.Errorf(vtrpcpb.Code_INTERNAL, "metadataRead: unhandled data type: %v", typ))
}
}
// readColumnCollationIDs reads from the optional metadata that exists.
// See: https://github.com/mysql/mysql-server/blob/8.0/libbinlogevents/include/rows_event.h
// What's included depends on the server configuration:
// https://dev.mysql.com/doc/refman/en/replication-options-binary-log.html#sysvar_binlog_row_metadata
// and the table definition.
// We only care about any collation IDs in the optional metadata and
// this info is provided in all binlog_row_metadata formats. Note that
// this info is only provided for text based columns.
func readColumnCollationIDs(data []byte, pos, count int) ([]collations.ID, error) {
collationIDs := make([]collations.ID, 0, count)
for pos < len(data) {
fieldType := uint8(data[pos])
pos++
fieldLen, read, ok := readLenEncInt(data, pos)View on GitHub (pinned to 01a25a7d17)
Solutions
- Use a supported binlog.Type* constant for every column in TableMap.Types.
- If the type is legitimate new MySQL metadata, add handling to metadataWrite, metadataRead, and metadataLength together.
- Validate type codes before constructing the TableMap.
Example fix
// before
tm.Types = []byte{0xAB} // not handled by metadataWrite
// after
tm.Types = []byte{binlog.TypeVarchar} Defensive patterns
Strategy: validation
Validate before calling
for c, typ := range tm.Types {
if !isWritableMetadataType(typ) {
return errors.Errorf("type %d at column %d has no metadata writer", typ, c)
}
} Try / catch
func safeNewTableMap(f mysql.BinlogFormat, s *mysql.FakeBinlogStream, id uint64, tm *mysql.TableMap) (ev mysql.BinlogEvent, err error) {
defer func() {
if r := recover(); r != nil {
err = fmt.Errorf("table map metadata write: %v", r)
}
}()
return mysql.NewTableMapEvent(f, s, id, tm), nil
} Prevention
- Only use column types supported by the metadata read/write pair.
- Add new types to metadataLength, metadataWrite, and metadataRead simultaneously.
- Sanitize binlog-sourced type codes before building TableMap structs.
When it happens
Trigger: Calling NewTableMapEvent with a TableMap.Types entry whose metadata cannot be written because the type byte is not one of the handled binlog types.
Common situations: Synthetic test types; type codes from a newer MySQL version not yet supported; mismatches where metadataLength accepts a type but metadataWrite does not (or vice versa).
Related errors
- metadataLength: unhandled data type: %v
- Not implemented, post_header_length!=8
- bad encoding
- Not implemented, post_header_length==6
- GetPreviousGTIDs: previous GTIDs not found
AI-assisted analysis of vitessio/vitess@01a25a7d17 (2026-09-01).
Data as JSON: /api/errors/484ca7e7778de783.
Report an issue: GitHub.