XTLS/Xray-core · error

invalid version component %s in %s

Error message

invalid version component %s in %s

What it means

Returned by compareVersions in app/version when the first version string (config.MinVersion/MaxVersion) contains a component that is not a plain decimal integer — strconv.Atoi fails on that dot-separated part. Both endpoints of the comparison can produce it; this one wraps the MinVersion-side component (v1). Versions must be numeric dotted triples/quads like 25.8.15; the parser does not accept suffixes.

Source

Thrown at app/version/version.go:57

func compareVersions(v1, v2 string) (int, error) {
	// Split version strings into components
	v1Parts := strings.Split(v1, ".")
	v2Parts := strings.Split(v2, ".")

	// Pad shorter versions with zeros
	for len(v1Parts) < len(v2Parts) {
		v1Parts = append(v1Parts, "0")
	}
	for len(v2Parts) < len(v1Parts) {
		v2Parts = append(v2Parts, "0")
	}

	// Compare each part
	for i := 0; i < len(v1Parts); i++ {
		// Convert parts to integers
		n1, err := strconv.Atoi(v1Parts[i])
		if err != nil {
			return 0, errors.New("invalid version component ", v1Parts[i], " in ", v1)
		}
		n2, err := strconv.Atoi(v2Parts[i])
		if err != nil {
			return 0, errors.New("invalid version component ", v2Parts[i], " in ", v2)
		}

		if n1 < n2 {
			return -1, nil // v1 < v2
		}
		if n1 > n2 {
			return 1, nil // v1 > v2
		}
	}
	return 0, nil // v1 == v2
}

func init() {
	common.Must(common.RegisterConfig((*Config)(nil), func(ctx context.Context, config interface{}) (interface{}, error) {

View on GitHub (pinned to 7d214f8b09)

Solutions

  1. Strip any leading 'v'/'V' and pre-release/build suffixes so every dot-separated component is an integer (e.g. "v25.8.15-beta" -> "25.8.15").
  2. Validate the version fields with a numeric-component check before writing configs (see validationCode).
  3. If you need pre-release gating, enforce it outside the config version pins; Xray compares numeric components only.

Example fix

// before (config)
"minVersion": "v25.8.15"

// after
"minVersion": "25.8.15"
Defensive patterns

Strategy: validation

Validate before calling

func validVersionPin(v string) bool {
    if v == "" { return true } // optional
    for _, p := range strings.Split(v, ".") {
        if _, err := strconv.Atoi(p); err != nil { return false }
    }
    return true
}
// reject config if !validVersionPin(cfg.MinVersion) || !validVersionPin(cfg.MaxVersion)

Type guard

func isNumericVersion(v string) bool {
    for _, p := range strings.Split(v, ".") {
        if _, err := strconv.Atoi(p); err != nil { return false }
    }
    return true
}

Prevention

When it happens

Trigger: A minVersion/maxVersion such as "v25.8.15" (leading 'v'), "25.8.15-beta" (pre-release suffix), "1.2.x", or an empty component "25..8". Any non-digit component in v1 raises this at startup during version.New.

Common situations: Hand-editing configs and pasting versions from release tags ('v' prefix from GitHub tags); tooling that appends build metadata; assuming semver pre-release strings are supported when only numeric parts are.

Related errors


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