vitessio/vitess · error

Numeric.ReverseMap: length of keyspaceId is not 8: %d

Error message

Numeric.ReverseMap: length of keyspaceId is not 8: %d

What it means

Numeric.ReverseMap expects every keyspace id to be exactly 8 bytes (a big-endian uint64). Any shorter/longer id means the keyspace id was not produced by the Numeric vindex, so it cannot be reversed to its numeric id. This usually signals the wrong vindex type is associated with the table or corrupted mapping data.

Source

Thrown at go/vt/vtgate/vindexes/numeric.go:104

func (vind *Numeric) Map(ctx context.Context, vcursor VCursor, ids []sqltypes.Value) ([]key.ShardDestination, error) {
	out := make([]key.ShardDestination, 0, len(ids))
	for _, id := range ids {
		ksid, err := vind.Hash(id)
		if err != nil {
			out = append(out, key.DestinationNone{})
			continue
		}
		out = append(out, key.DestinationKeyspaceID(ksid))
	}
	return out, nil
}

// ReverseMap returns the associated ids for the ksids.
func (*Numeric) ReverseMap(_ VCursor, ksids [][]byte) ([]sqltypes.Value, error) {
	reverseIds := make([]sqltypes.Value, len(ksids))
	for i, keyspaceID := range ksids {
		if len(keyspaceID) != 8 {
			return nil, fmt.Errorf("Numeric.ReverseMap: length of keyspaceId is not 8: %d", len(keyspaceID))
		}
		val := binary.BigEndian.Uint64(keyspaceID)
		reverseIds[i] = sqltypes.NewUint64(val)
	}
	return reverseIds, nil
}

// RangeMap implements Between.
func (vind *Numeric) RangeMap(ctx context.Context, vcursor VCursor, startId sqltypes.Value, endId sqltypes.Value) ([]key.ShardDestination, error) {
	startKsId, err := vind.Hash(startId)
	if err != nil {
		return nil, err
	}
	endKsId, err := vind.Hash(endId)
	if err != nil {
		return nil, err
	}
	out := []key.ShardDestination{&key.DestinationKeyRange{KeyRange: key.NewKeyRange(startKsId, endKsId)}}

View on GitHub (pinned to 01a25a7d17)

Solutions

  1. Confirm the vindex type in the vschema matches the one that generated the keyspace ids (numeric -> 8 bytes).
  2. If the table used a different vindex (e.g. binary_md5, 16 bytes), use that vindex type for reversal.
  3. Rebuild the mapping/lookup data with the correct vindex before running reverse workflows.

Example fix

// before (vschema)
"vindex": {"type": "numeric"}  // but keys are 16-byte md5
// after
"vindex": {"type": "binary_md5"}
Defensive patterns

Strategy: validation

Validate before calling

for _, ksid := range ksids {
    if len(ksid) != 8 {
        return errors.New("keyspace ids are not from a Numeric vindex")
    }
}

Type guard

func isNumericKeyspaceID(k []byte) bool { return len(k) == 8 }

Prevention

When it happens

Trigger: Calling ReverseMap on a Numeric vindex with a keyspace id whose length != 8, e.g. during vindex reversal workflows (MoveTables/Reshard reverse lookup) when the mapping table contains ids generated by a different vindex (Binary, Hash produce 8 bytes too, but BinaryMD5 produces 16).

Common situations: Table was migrated from another vindex type (e.g. binary_md5) but the vschema now claims numeric; lookup/reverse workflow fed with mixed-length keyspace ids; manually crafted keyspace ids in test code.

Related errors


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