{"record":{"id":"86d162b4dff6cc63","repo":"XTLS/Xray-core","slug":"this-config-should-be-run-on-version-s-or-lower","errorCode":null,"errorMessage":"this config should be run on version %s or lower","messagePattern":"this config should be run on version (.+?) or lower","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"critical","filePath":"app/version/version.go","lineNumber":33,"sourceCode":"}\n\nfunc New(ctx context.Context, config *Config) (*Version, error) {\n\tif config.MinVersion != \"\" {\n\t\tresult, err := compareVersions(config.MinVersion, config.CoreVersion)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tif result > 0 {\n\t\t\treturn nil, errors.New(\"this config must be run on version \", config.MinVersion, \" or higher\")\n\t\t}\n\t}\n\tif config.MaxVersion != \"\" {\n\t\tresult, err := compareVersions(config.MaxVersion, config.CoreVersion)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tif result < 0 {\n\t\t\treturn nil, errors.New(\"this config should be run on version \", config.MaxVersion, \" or lower\")\n\t\t}\n\t}\n\treturn &Version{config: config, ctx: ctx}, nil\n}\n\nfunc compareVersions(v1, v2 string) (int, error) {\n\t// Split version strings into components\n\tv1Parts := strings.Split(v1, \".\")\n\tv2Parts := strings.Split(v2, \".\")\n\n\t// Pad shorter versions with zeros\n\tfor len(v1Parts) < len(v2Parts) {\n\t\tv1Parts = append(v1Parts, \"0\")\n\t}\n\tfor len(v2Parts) < len(v1Parts) {\n\t\tv2Parts = append(v2Parts, \"0\")\n\t}\n","sourceCodeStart":15,"sourceCodeEnd":51,"githubUrl":"https://github.com/XTLS/Xray-core/blob/7d214f8b094f75322fa3990f8aadad1c912f24f5/app/version/version.go#L15-L51","documentation":"Returned by version.New when the config declares a MaxVersion strictly lower than the running core version — i.e. the config is known to be incompatible with cores newer than MaxVersion. compareVersions(MaxVersion, CoreVersion) < 0 triggers it. This usually means the core binary is newer than the config format expects (e.g. pre-release config used on a stable, changed core).","triggerScenarios":"Running a config that pins maxVersion (typical of configs generated for a specific release line) on a newer xray build; downgrading a config's expected core while keeping an upgraded binary.","commonSituations":"Rolling back a panel that emits maxVersion pins while the server binary stayed upgraded; using experimental configs on stable cores after a breaking release.","solutions":["Regenerate or edit the config to raise/remove maxVersion once compatibility with the new core is confirmed.","Alternatively downgrade the xray-core binary to the pinned line.","Keep configs free of version pins unless a known incompatibility exists, so routine core upgrades do not brick startup."],"exampleFix":"// before (config)\n\"maxVersion\": \"24.11.30\" // core is 25.8.15 -> startup fails\n\n// after\n\"maxVersion\": \"\" // or bump to current core version","handlingStrategy":"validation","validationCode":"if cfg.MaxVersion != \"\" {\n    if c, err := versionCompare(cfg.MaxVersion, coreVer); err == nil && c < 0 {\n        // regenerate config without the pin, or downgrade binary\n    }\n}","typeGuard":"func isNumericVersion(v string) bool {\n    if v == \"\" { return false }\n    for _, p := range strings.Split(v, \".\") {\n        if _, err := strconv.Atoi(p); err != nil { return false }\n    }\n    return true\n}","tryCatchPattern":"_, err := version.New(ctx, vcfg)\nif err != nil { /* config/core mismatch: align versions before retry */ }","preventionTips":["Avoid maxVersion pins unless a known incompatibility exists","Regenerate configs with the matching panel/core release"],"tags":["version","config","startup","xray"],"backgroundTag":null,"analyzedSha":"7d214f8b094f75322fa3990f8aadad1c912f24f5","analyzedAt":"2026-08-15T14:26:24.325Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}