XTLS/Xray-core · error

Invalid integer range, expected either string of form "1-2"

Error message

Invalid integer range, expected either string of form "1-2" or plain integer.

What it means

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.

Source

Thrown at infra/conf/common.go:329

// UnmarshalJSON implements encoding/json.Unmarshaler.UnmarshalJSON
func (v *Int32Range) UnmarshalJSON(data []byte) error {
	defer v.ensureOrder()
	var str string
	var rawint int32
	if err := json.Unmarshal(data, &str); err == nil {
		left, right, err := ParseRangeString(str)
		if err == nil {
			v.Left, v.Right = int32(left), int32(right)
			return nil
		}
	} else if err := json.Unmarshal(data, &rawint); err == nil {
		v.Left = rawint
		v.Right = rawint
		return nil
	}

	return errors.New("Invalid integer range, expected either string of form \"1-2\" or plain integer.")
}

// ensureOrder() gives value to .From & .To and make sure .From < .To
func (r *Int32Range) ensureOrder() {
	r.From, r.To = r.Left, r.Right
	if r.From > r.To {
		r.From, r.To = r.To, r.From
	}
}

// "-114-514"   →  ["-114","514"]
// "-1919--810" →  ["-1919","-810"]
func splitFromSecondDash(s string) []string {
	parts := strings.SplitN(s, "-", 3)
	if len(parts) < 3 {
		return []string{s}
	}
	return []string{parts[0] + "-" + parts[1], parts[2]}

View on GitHub (pinned to 7d214f8b09)

Solutions

  1. Use a string range: "length": "100-200"
  2. Or a single integer which becomes both Left and Right: "length": 100
  3. Never use a JSON array or floating point for these fields

Example fix

// before
"length": [100, 200]

// after
"length": "100-200"
Defensive patterns

Strategy: type-guard

Validate before calling

func validateInt32RangeJSON(raw []byte) error {
    var i int32
    if json.Unmarshal(raw, &i) == nil {
        return nil
    }
    var s string
    if json.Unmarshal(raw, &s) == nil {
        if matched, _ := regexp.MatchString(`^-?\d+-(-)?\d+$|^\d+$`, s); matched {
            return nil
        }
    }
    return errors.New("expected integer or \"min-max\" string")
}

Type guard

func isInt32Range(v any) bool {
    switch t := v.(type) {
    case float64:
        return t == float64(int32(t))
    case string:
        _, _, err := conf.ParseRangeString(t) // or a local -?\d+-\d+ regex
        return err == nil
    }
    return false
}

Try / catch

if err := json.Unmarshal(data, &r); err != nil {
    if strings.Contains(err.Error(), "Invalid integer range") {
        return fmt.Errorf("field must be 100 or \"100-200\", not an array/float/null")
    }
    return err
}

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Related errors


AI-assisted analysis of XTLS/Xray-core@7d214f8b09 (2026-08-15). Data as JSON: /api/errors/bcc9f27aab8a0de9. Report an issue: GitHub.