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

  1. Use a supported binlog.Type* constant for every column in TableMap.Types.
  2. If the type is legitimate new MySQL metadata, add handling to metadataWrite, metadataRead, and metadataLength together.
  3. 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

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


AI-assisted analysis of vitessio/vitess@01a25a7d17 (2026-09-01). Data as JSON: /api/errors/484ca7e7778de783. Report an issue: GitHub.