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
- 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").
- Validate the version fields with a numeric-component check before writing configs (see validationCode).
- 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
- Strip 'v' prefixes and pre-release suffixes when generating configs
- Lint config version fields in CI
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
- this config must be run on version %s or higher
- this config should be run on version %s or lower
- varint overflow
- invalid body length:
- illegal ip rule:
AI-assisted analysis of XTLS/Xray-core@7d214f8b09 (2026-08-15).
Data as JSON: /api/errors/83b088043a4015e8.
Report an issue: GitHub.