vitessio/vitess · error

metadataLength: unhandled data type

Error message

metadataLength: unhandled data type: %v

What it means

metadataLength computes the byte size of the optional metadata for a column type; for unrecognized types it panics with a vterrors INTERNAL error, since this path is expected only in tests with synthetic types. Valid production binlog types never reach the default branch.

Solutions

  1. Replace the unsupported type byte with a valid binlog.Type* constant.
  2. Add the missing type to metadataLength (and the matching read/write functions) if it is a real new MySQL type.
  3. Sanitize the TableMap before building events, rejecting unknown type codes with a proper error.

Example fix

// before
tm.Types = []byte{0x99} // unknown
ev := mysql.NewTableMapEvent(f, s, id, tm) // panics
// after
tm.Types = []byte{binlog.TypeFloat}
ev := mysql.NewTableMapEvent(f, s, id, tm)
Defensive patterns

Strategy: validation

Validate before calling

for _, typ := range tm.Types {
    if !isKnownBinlogType(typ) {
        return errors.Errorf("unknown column type %d before building table map", typ)
    }
}

Try / catch

func safeMetadataTotal(types []byte) (n int, err error) {
    defer func() {
        if r := recover(); r != nil {
            err = fmt.Errorf("metadataLength: %v", r)
        }
    }()
    return mysql.MetadataTotalLength(types), nil
}

Prevention

When it happens

Trigger: Calling NewTableMapEvent (via metadataTotalLength -> metadataLength) with a TableMap.Types entry containing a byte that is not a supported MySQL column type.

Common situations: Unit tests using made-up type bytes; corrupted or truncated binlog data supplying invalid type codes; new upstream MySQL types not yet added to the switch.

Related errors


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

Appendix: source

Thrown at go/mysql/binlog_event_rbr.go:154

	case binlog.TypeDecimal, binlog.TypeTiny, binlog.TypeShort, binlog.TypeLong, binlog.TypeNull, binlog.TypeTimestamp, binlog.TypeLongLong, binlog.TypeInt24, binlog.TypeDate, binlog.TypeTime, binlog.TypeDateTime, binlog.TypeYear, binlog.TypeNewDate:
		// No data here.
		return 0

	case binlog.TypeFloat, binlog.TypeDouble, binlog.TypeTimestamp2, binlog.TypeDateTime2, binlog.TypeTime2, binlog.TypeJSON, binlog.TypeTinyBlob, binlog.TypeMediumBlob, binlog.TypeLongBlob, binlog.TypeBlob, binlog.TypeGeometry, binlog.TypeVector:
		// One byte.
		return 1

	case binlog.TypeNewDecimal, binlog.TypeEnum, binlog.TypeSet, binlog.TypeString:
		// Two bytes, Big Endian because of crazy encoding.
		return 2

	case binlog.TypeVarchar, binlog.TypeBit, binlog.TypeVarString:
		// Two bytes, Little Endian
		return 2

	default:
		// Unknown type. This is used in tests only, so panic.
		panic(vterrors.Errorf(vtrpcpb.Code_INTERNAL, "metadataLength: unhandled data type: %v", typ))
	}
}

// metadataTotalLength returns the total size of the metadata for an
// array of types.
func metadataTotalLength(types []byte) int {
	sum := 0
	for _, t := range types {
		sum += metadataLength(t)
	}
	return sum
}

// metadataRead reads a single value from the metadata string.
func metadataRead(data []byte, pos int, typ byte) (uint16, int, error) {
	switch typ {
	case binlog.TypeDecimal, binlog.TypeTiny, binlog.TypeShort, binlog.TypeLong, binlog.TypeNull, binlog.TypeTimestamp, binlog.TypeLongLong, binlog.TypeInt24, binlog.TypeDate, binlog.TypeTime, binlog.TypeDateTime, binlog.TypeYear, binlog.TypeNewDate:
		// No data here.

View on GitHub (pinned to 01a25a7d17)