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
- Fix the spec so only the first and last limits may be empty: e.g. '-80,80-' or '0-80,80-'.
- Replace mid-spec empty limits with explicit hex boundaries (e.g. use the actual boundary value).
- Validate the spec with ParseShardingSpec in a test or preflight script before deploying topo config.
- 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
- Only place MinKey ('') as the first limit and MaxKey ('') as the last limit
- Validate specs with ParseShardingSpec in unit tests before deploying
- Avoid hand-editing spec strings; generate them programmatically
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
- Parsing and encoding errors: unexpected token, malformed input — why parsers reject input and how to find the real culprit.
Related errors
- malformed spec: shard limits should be in order: %q
- the shard count must be > 0: %v
- the index of the shard must be less than the total number of
- the shard count must be a power of two: %v
- the given number of shards (%d) is too high for the given nu
AI-assisted analysis of vitessio/vitess@01a25a7d17 (2026-09-01).
Data as JSON: /api/errors/489274b15903d287.
Report an issue: GitHub.