{"record":{"id":"bcc9f27aab8a0de9","repo":"XTLS/Xray-core","slug":"invalid-integer-range-expected-either-string-of-f","errorCode":null,"errorMessage":"Invalid integer range, expected either string of form \"1-2\" or plain integer.","messagePattern":"Invalid integer range, expected either string of form \"1-2\" or plain integer\\.","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"infra/conf/common.go","lineNumber":329,"sourceCode":"\n// UnmarshalJSON implements encoding/json.Unmarshaler.UnmarshalJSON\nfunc (v *Int32Range) UnmarshalJSON(data []byte) error {\n\tdefer v.ensureOrder()\n\tvar str string\n\tvar rawint int32\n\tif err := json.Unmarshal(data, &str); err == nil {\n\t\tleft, right, err := ParseRangeString(str)\n\t\tif err == nil {\n\t\t\tv.Left, v.Right = int32(left), int32(right)\n\t\t\treturn nil\n\t\t}\n\t} else if err := json.Unmarshal(data, &rawint); err == nil {\n\t\tv.Left = rawint\n\t\tv.Right = rawint\n\t\treturn nil\n\t}\n\n\treturn errors.New(\"Invalid integer range, expected either string of form \\\"1-2\\\" or plain integer.\")\n}\n\n// ensureOrder() gives value to .From & .To and make sure .From < .To\nfunc (r *Int32Range) ensureOrder() {\n\tr.From, r.To = r.Left, r.Right\n\tif r.From > r.To {\n\t\tr.From, r.To = r.To, r.From\n\t}\n}\n\n// \"-114-514\"   →  [\"-114\",\"514\"]\n// \"-1919--810\" →  [\"-1919\",\"-810\"]\nfunc splitFromSecondDash(s string) []string {\n\tparts := strings.SplitN(s, \"-\", 3)\n\tif len(parts) < 3 {\n\t\treturn []string{s}\n\t}\n\treturn []string{parts[0] + \"-\" + parts[1], parts[2]}","sourceCodeStart":311,"sourceCodeEnd":347,"githubUrl":"https://github.com/XTLS/Xray-core/blob/7d214f8b094f75322fa3990f8aadad1c912f24f5/infra/conf/common.go#L311-L347","documentation":"Thrown by Int32Range.UnmarshalJSON in infra/conf/common.go when the JSON value is neither a string that ParseRangeString can parse as 'left-right' nor a plain JSON integer. The code first tries the string form (including ranges), then a raw integer form; failure of both produces this message.","triggerScenarios":"Fields typed conf.Int32Range (e.g.Freedom strategy 'settings.frag' related length ranges in recent Xray, Mux 'xudp' unrelated) given values like \"range\": [1,2] (array), \"range\": \"abc\", \"range\": 1.5, or \"range\": null.","commonSituations":"Users assuming a two-element array [min,max] works (it does not — use a \"min-max\" string or a single int); quoting is required for ranges but not for single values; float values are rejected.","solutions":["Use a string range: \"length\": \"100-200\"","Or a single integer which becomes both Left and Right: \"length\": 100","Never use a JSON array or floating point for these fields"],"exampleFix":"// before\n\"length\": [100, 200]\n\n// after\n\"length\": \"100-200\"","handlingStrategy":"type-guard","validationCode":"func validateInt32RangeJSON(raw []byte) error {\n    var i int32\n    if json.Unmarshal(raw, &i) == nil {\n        return nil\n    }\n    var s string\n    if json.Unmarshal(raw, &s) == nil {\n        if matched, _ := regexp.MatchString(`^-?\\d+-(-)?\\d+$|^\\d+$`, s); matched {\n            return nil\n        }\n    }\n    return errors.New(\"expected integer or \\\"min-max\\\" string\")\n}","typeGuard":"func isInt32Range(v any) bool {\n    switch t := v.(type) {\n    case float64:\n        return t == float64(int32(t))\n    case string:\n        _, _, err := conf.ParseRangeString(t) // or a local -?\\d+-\\d+ regex\n        return err == nil\n    }\n    return false\n}","tryCatchPattern":"if err := json.Unmarshal(data, &r); err != nil {\n    if strings.Contains(err.Error(), \"Invalid integer range\") {\n        return fmt.Errorf(\"field must be 100 or \\\"100-200\\\", not an array/float/null\")\n    }\n    return err\n}","preventionTips":["Never use [min,max] arrays for range fields","Quote ranges; leave single values unquoted or quoted integers"],"tags":["config","validation","json","xray"],"backgroundTag":null,"analyzedSha":"7d214f8b094f75322fa3990f8aadad1c912f24f5","analyzedAt":"2026-08-15T14:26:24.325Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}