{"record":{"id":"f25131d1cae414eb","repo":"vitessio/vitess","slug":"range-d-should-be-d","errorCode":null,"errorMessage":"range %d should be >= %d","messagePattern":"range (.+?) should be >= (.+?)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"go/mysql/json/json_path.go","lineNumber":597,"sourceCode":"\t\treturn in[2:], nil\n\t}\n\treturn nil, errInvalid\n}\n\nfunc stepArrayLocationTo(p *PathParser, in []byte) ([]byte, error) {\n\tvar skip int\n\tin, skip = trim(in)\n\tif in == nil || skip == 0 {\n\t\treturn nil, errInvalid\n\t}\n\tif in[0] >= '0' && in[0] <= '9' {\n\t\tp.step = stepArrayLocationClose\n\t\toffset, in2, err := p.lexNumeric(in)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tif offset <= p.path.offset0 {\n\t\t\treturn nil, fmt.Errorf(\"range %d should be >= %d\", offset, p.path.offset0)\n\t\t}\n\t\tp.path.offset1 = offset\n\t\treturn in2, nil\n\t}\n\tif bytes.HasPrefix(in, []byte{'l', 'a', 's', 't'}) {\n\t\tp.step = stepArrayLocationLast1\n\t\tp.path.offset1 = -1\n\t\treturn in[4:], nil\n\t}\n\treturn nil, errInvalid\n}\n\nfunc stepArrayLocationClose(p *PathParser, in []byte) ([]byte, error) {\n\tif in, _ = trim(in); in == nil {\n\t\treturn nil, errInvalid\n\t}\n\tif in[0] == ']' {\n\t\tp.step = stepPathLeg","sourceCodeStart":579,"sourceCodeEnd":615,"githubUrl":"https://github.com/vitessio/vitess/blob/01a25a7d176f94613b8d59d799f438380a8760e4/go/mysql/json/json_path.go#L579-L615","documentation":"While parsing a JSON path range clause, the second offset (the range end) must be strictly greater than the first offset (offset0). The parser in go/mysql/json/json_path.go rejects clauses like '$[1 to 1]' or '$[3 to 2]' where the range end is not greater than the range start. This enforces MySQL's semantics that a range must cover at least one element.","triggerScenarios":"Evaluating or parsing a JSON path with a 'to' range where the second numeric location is less than or equal to the first, e.g. stepArrayLocationTo reading '$.a[2 to 2]' or '$.a[5 to 1]', including cases where both values are negative or the second offset was already consumed as offset0.","commonSituations":"User-supplied JSON path strings from application code or SQL queries with typos in range bounds; programmatically generated ranges where start and end are equal (empty range) or reversed; off-by-one in code computing range endpoints.","solutions":["Fix the JSON path so the range end is strictly greater than the start, e.g. '$[1 to 3]' instead of '$[1 to 1]'","If you need a single element, use a plain index like '$[1]' instead of an empty range","Validate/clamp range bounds in application code before passing the path string to the parser","Swap reversed bounds (use min as start, max as end) before parsing"],"exampleFix":"// before\npath := \"$.items[2 to 2]\"\n// after\npath := \"$.items[2]\" // or \"$.items[2 to 3]\"","handlingStrategy":"validation","validationCode":"func validRange(p string) error {\n    // e.g. \"$.a[1 to 3]\": ensure end > start\n    if start, end, ok := parseRangeBounds(p); ok && end <= start {\n        return fmt.Errorf(\"range end %d must be > start %d\", end, start)\n    }\n    return nil\n}","typeGuard":null,"tryCatchPattern":"if _, err := json.NormalizePath(userPath); err != nil {\n    if strings.Contains(err.Error(), \"should be >=\") {\n        return fmt.Errorf(\"invalid JSON path range in %q: %w\", userPath, err)\n    }\n    return err\n}","preventionTips":["Use single indexes instead of ranges when start and end could be equal","Validate/clamp range bounds before formatting the path string","Sanitize user-supplied JSON paths before parsing","Never emit 'x to x' or reversed ranges from generated path builders"],"tags":["go","json","json-path","parsing","validation"],"backgroundTag":"invalid-json-path","analyzedSha":"01a25a7d176f94613b8d59d799f438380a8760e4","analyzedAt":"2026-09-01T17:28:30.605Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}