vitessio/vitess · error

malformed spec: shard limits should be in order: %q

Error message

malformed spec: shard limits should be in order: %q

What it means

ParseShardingSpec requires shard limits to be strictly increasing. Because boundaries are compared as strings, each hex-encoded limit must sort after the previous one. The library throws this when a limit is equal to or lower than the preceding limit, since keyranges must be non-overlapping and ordered.

Source

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

// 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
		}
		ranges[i] = &topodatapb.KeyRange{Start: s, End: e}
		old = p
	}

View on GitHub (pinned to 01a25a7d17)

Solutions

  1. Rewrite the spec so every boundary is strictly greater than the previous one, e.g. '0-40,40-80,80-'.
  2. Remove duplicate boundary values.
  3. Confirm limits are consistently hex-encoded and uppercase/lowercase consistent so string ordering matches numeric ordering.
  4. Validate the spec programmatically before saving it to topo config.

Example fix

// before
ParseShardingSpec("80-40,40-") // limits out of order
// after
ParseShardingSpec("-40,40-80,80-")
Defensive patterns

Strategy: validation

Validate before calling

func limitsInOrder(spec string) bool {
	parts := strings.Split(spec, "-")
	for i := 1; i < len(parts); i++ {
		if parts[i] != "" && parts[i] <= parts[i-1] {
			return false
		}
	}
	return true
}

Try / catch

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

Prevention

When it happens

Trigger: Calling ParseShardingSpec with out-of-order or duplicate limits, e.g. '80-40,40-' or '80-80,80-'. Fires when parts[1:][i] != "" and p <= old (string comparison of hex values).

Common situations: Typo in hex boundaries when writing keyspace configs, specs copied from a different keyspace with different boundaries, automated spec generation that didn't sort segments, mixing case or wrong-length hex strings so string ordering diverges from intent.

Understand the failure class

Related errors


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