{"record":{"id":"57a84792b67d6df9","repo":"vitessio/vitess","slug":"malformed-spec-doesn-t-define-a-range-q","errorCode":null,"errorMessage":"malformed spec: doesn't define a range: %q","messagePattern":"malformed spec: doesn't define a range: %q","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"go/vt/key/key.go","lineNumber":287,"sourceCode":"\t\treturn true\n\t}\n\n\treturn false\n}\n\n// ParseShardingSpec parses a string that describes a sharding\n// specification. a-b-c-d will be parsed as a-b, b-c, c-d. The empty\n// string may serve both as the start and end of the keyspace: -a-b-\n// will be parsed as start-a, a-b, b-end.\n// \"0\" is treated as \"-\", to allow us to not have to special-case\n// client code.\nfunc ParseShardingSpec(spec string) ([]*topodatapb.KeyRange, error) {\n\tparts := strings.Split(spec, \"-\")\n\tif len(parts) == 1 {\n\t\tif spec == \"0\" {\n\t\t\tparts = []string{\"\", \"\"}\n\t\t} else {\n\t\t\treturn nil, fmt.Errorf(\"malformed spec: doesn't define a range: %q\", spec)\n\t\t}\n\t}\n\told := parts[0]\n\tranges := make([]*topodatapb.KeyRange, len(parts)-1)\n\n\tfor i, p := range parts[1:] {\n\t\tif p == \"\" && i != (len(parts)-2) {\n\t\t\treturn nil, fmt.Errorf(\"malformed spec: MinKey/MaxKey cannot be in the middle of the spec: %q\", spec)\n\t\t}\n\t\tif p != \"\" && p <= old {\n\t\t\treturn nil, fmt.Errorf(\"malformed spec: shard limits should be in order: %q\", spec)\n\t\t}\n\t\ts, err := hex.DecodeString(old)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tif len(s) == 0 {\n\t\t\ts = nil","sourceCodeStart":269,"sourceCodeEnd":305,"githubUrl":"https://github.com/vitessio/vitess/blob/01a25a7d176f94613b8d59d799f438380a8760e4/go/vt/key/key.go#L269-L305","documentation":"ParseShardingSpec splits a sharding spec like '00-80,80-' on '-' to build KeyRanges. A single-part spec is only allowed if it is exactly \"0\" (meaning the full range); any other token without a dash cannot define a range and yields this error. It is a configuration-format validation error on the sharding spec string.","triggerScenarios":"Calling ParseShardingSpec (directly or via initShardArray) with a spec string containing no '-' and not equal to \"0\" — e.g. \"80\", \"abc\", or an empty/whitespace spec.","commonSituations":"Typos in sharding specs in topo/config files (missing the second boundary, e.g. \"00\" instead of \"00-80\"); pasting a single keyspace id instead of a range; users unaware that only \"0\" is the valid one-token form.","solutions":["Rewrite the spec as a proper range 'start-end' (e.g. \"0\" or \"00-80,80-\")","If you meant the full keyspace range, use the spec \"0\" exactly","Check for copy/paste truncation that dropped the '-<end>' half of the range"],"exampleFix":"// before\nkey.ParseShardingSpec(\"80\")   // error\n// after\nkey.ParseShardingSpec(\"80-\")  // range from 80 to the end\nkey.ParseShardingSpec(\"00-80\")","handlingStrategy":"validation","validationCode":"func validShardingSpec(spec string) error {\n    if spec == \"0\" { return nil }\n    for _, part := range strings.Split(spec, \",\") {\n        if !strings.Contains(part, \"-\") {\n            return fmt.Errorf(\"sharding spec part %q must be a range 'start-end'\", part)\n        }\n    }\n    return nil\n}","typeGuard":null,"tryCatchPattern":"krs, err := key.ParseShardingSpec(spec)\nif err != nil {\n    return fmt.Errorf(\"bad sharding spec %q: %w\", spec, err)\n}","preventionTips":["Validate sharding specs at config-load time, before topo writes","Remember the only valid single-token spec is \"0\"; everything else needs 'start-end'","Lint config files for specs that lost their '-' during templating or copy/paste"],"tags":["validation","sharding","configuration"],"backgroundTag":"invalid-sharding-spec","analyzedSha":"01a25a7d176f94613b8d59d799f438380a8760e4","analyzedAt":"2026-09-01T17:28:30.605Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}