{"record":{"id":"218263fd45ba7e91","repo":"XTLS/Xray-core","slug":"syntax-error","errorCode":null,"errorMessage":"syntax error","messagePattern":"syntax error","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"common/geodata/rule_parser.go","lineNumber":62,"sourceCode":"\t\tipRules = append(ipRules, &IPRule{Value: rule})\n\t}\n\n\treturn ipRules, nil\n}\n\nfunc cutReversePrefix(s string) (string, bool) {\n\treverse := false\n\tfor strings.HasPrefix(s, \"!\") {\n\t\ts = s[1:]\n\t\treverse = !reverse\n\t}\n\treturn s, reverse\n}\n\nfunc parseGeoIPRule(rule string, reverse bool) (*IPRule_Geoip, error) {\n\tfile, code, ok := strings.Cut(rule, \":\")\n\tif !ok {\n\t\treturn nil, errors.New(\"syntax error\")\n\t}\n\n\tif file == \"\" {\n\t\treturn nil, errors.New(\"empty file\")\n\t}\n\n\tcode, codeReverse := cutReversePrefix(code)\n\treverse = reverse != codeReverse\n\tif code == \"\" {\n\t\treturn nil, errors.New(\"empty code\")\n\t}\n\tcode = strings.ToUpper(code)\n\n\tif err := checkFile(file, code); err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn &IPRule_Geoip{","sourceCodeStart":44,"sourceCodeEnd":80,"githubUrl":"https://github.com/XTLS/Xray-core/blob/7d214f8b094f75322fa3990f8aadad1c912f24f5/common/geodata/rule_parser.go#L44-L80","documentation":"parseGeoIPRule splits the rule on ':' via strings.Cut; if there is no ':' at all, ok is false and this error is raised. It means the caller routed a rule into the GeoIP branch (prefix > 0 or ext:/geosite-style handling) but the string lacks the required FILE:CODE shape.","triggerScenarios":"A rule string beginning with a recognized prefix but containing no colon, e.g. \"ext:geoip.dat\" is fine but a custom path like \"ext\" or \"geoip-only-cn\" (no ':') reaching this parser.","commonSituations":"Forgetting the country code segment: \"ext:geoip.dat\" instead of \"ext:geoip.dat:cn\"; omitting code after \"geosite:\" style aliasing when the alias is missing.","solutions":["Rewrite the rule as FILE:CODE, e.g. \"ext:geoip.dat:cn\" or \"geoip:cn\".","For plain CIDR/IP rules (no file), drop the prefix so parseCustomIPRule handles them."],"exampleFix":"// before\n\"ip\": [\"ext:geoip.dat\"]\n\n// after\n\"ip\": [\"ext:geoip.dat:cn\"]","handlingStrategy":"validation","validationCode":"if strings.HasPrefix(r, \"ext:\") || strings.HasPrefix(r, \"geoip\") {\n    if !strings.Contains(r, \":\") || strings.HasSuffix(r, \":\") { return fmt.Errorf(\"rule %q must be FILE:CODE\", r) }\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Template geoip rules as \"geoip:CODE\" and ext rules as \"ext:FILE.dat:CODE\" so the colon is never omitted."],"tags":["geodata","ip-rule","syntax","xray"],"backgroundTag":null,"analyzedSha":"7d214f8b094f75322fa3990f8aadad1c912f24f5","analyzedAt":"2026-08-15T14:26:24.325Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}