vitessio/vitess · error

malformed spec: MinKey/MaxKey cannot be in the middle of the

Error message

malformed spec: MinKey/MaxKey cannot be in the middle of the spec: %q

What it means

ParseShardingSpec parses a sharding spec string like '0-80,80-' into a list of KeyRange objects. Empty strings in the spec represent MinKey (start of keyspace) or MaxKey (end of keyspace); they are only legal as the first or last limit. The library throws this when an empty limit appears in any other position, which would produce an unbounded/meaningless keyrange in the middle of the shard map.

Source

Thrown at go/vt/key/key.go:295

// string may serve both as the start and end of the keyspace: -a-b-
// will be parsed as start-a, a-b, b-end.
// "0" is treated as "-", to allow us to not have to special-case
// client code.
func ParseShardingSpec(spec string) ([]*topodatapb.KeyRange, error) {
	parts := strings.Split(spec, "-")
	if len(parts) == 1 {
		if spec == "0" {
			parts = []string{"", ""}
		} else {
			return nil, fmt.Errorf("malformed spec: doesn't define a range: %q", spec)
		}
	}
	old := parts[0]
	ranges := make([]*topodatapb.KeyRange, len(parts)-1)

	for i, p := range parts[1:] {
		if p == "" && i != (len(parts)-2) {
			return nil, fmt.Errorf("malformed spec: MinKey/MaxKey cannot be in the middle of the spec: %q", spec)
		}
		if p != "" && p <= old {
			return nil, fmt.Errorf("malformed spec: shard limits should be in order: %q", spec)
		}
		s, err := hex.DecodeString(old)
		if err != nil {
			return nil, err
		}
		if len(s) == 0 {
			s = nil
		}
		e, err := hex.DecodeString(p)
		if err != nil {
			return nil, err
		}
		if len(e) == 0 {
			e = nil
		}

View on GitHub (pinned to 01a25a7d17)

Solutions

  1. Fix the spec so only the first and last limits may be empty: e.g. '-80,80-' or '0-80,80-'.
  2. Replace mid-spec empty limits with explicit hex boundaries (e.g. use the actual boundary value).
  3. Validate the spec with ParseShardingSpec in a test or preflight script before deploying topo config.
  4. Check for duplicated commas or accidental MinKey ('-') tokens in the middle when editing keyspace sharding settings.

Example fix

// before
ParseShardingSpec("0-,80-") // error: MinKey in the middle
// after
ParseShardingSpec("-80,80-") // MinKey only as first limit
Defensive patterns

Strategy: validation

Validate before calling

func validSpec(spec string) bool {
	parts := strings.Split(spec, "-")
	for i, p := range parts[1:] {
		if p == "" && i != len(parts)-2 {
			return false
		}
	}
	return true
}

Try / catch

kr, err := key.ParseShardingSpec(spec)
if err != nil {
	return fmt.Errorf("invalid sharding spec %q: %w", spec, err)
}

Prevention

When it happens

Trigger: Calling ParseShardingSpec with a spec string containing an empty segment before the final position, e.g. '0-,80-' or '0-,-' or '-80-'. The check fires when parts[1:][i] == "" and i != len(parts)-2 (i.e., the empty limit is not the last element).

Common situations: Hand-written sharding specs in vtctld/topo configuration with a stray or missing hex boundary, scripted generation of shard specs that leaves empty limits mid-list, copy-paste errors like '80-,80-,'.

Understand the failure class

Related errors


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