{"record":{"id":"5e9a66e4d0f6a927","repo":"XTLS/Xray-core","slug":"empty-balancer-tag","errorCode":null,"errorMessage":"empty balancer tag","messagePattern":"empty balancer tag","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"infra/conf/router.go","lineNumber":31,"sourceCode":")\n\n// StrategyConfig represents a strategy config\ntype StrategyConfig struct {\n\tType     string           `json:\"type\"`\n\tSettings *json.RawMessage `json:\"settings\"`\n}\n\ntype BalancingRule struct {\n\tTag         string         `json:\"tag\"`\n\tSelectors   StringList     `json:\"selector\"`\n\tStrategy    StrategyConfig `json:\"strategy\"`\n\tFallbackTag string         `json:\"fallbackTag\"`\n}\n\n// Build builds the balancing rule\nfunc (r *BalancingRule) Build() (*router.BalancingRule, error) {\n\tif r.Tag == \"\" {\n\t\treturn nil, errors.New(\"empty balancer tag\")\n\t}\n\tif len(r.Selectors) == 0 {\n\t\treturn nil, errors.New(\"empty selector list\")\n\t}\n\n\tr.Strategy.Type = strings.ToLower(r.Strategy.Type)\n\tswitch r.Strategy.Type {\n\tcase \"\":\n\t\tr.Strategy.Type = strategyRandom\n\tcase strategyRandom, strategyLeastLoad, strategyLeastPing, strategyRoundRobin:\n\tdefault:\n\t\treturn nil, errors.New(\"unknown balancing strategy: \" + r.Strategy.Type)\n\t}\n\n\tsettings := []byte(\"{}\")\n\tif r.Strategy.Settings != nil {\n\t\tsettings = ([]byte)(*r.Strategy.Settings)\n\t}","sourceCodeStart":13,"sourceCodeEnd":49,"githubUrl":"https://github.com/XTLS/Xray-core/blob/7d214f8b094f75322fa3990f8aadad1c912f24f5/infra/conf/router.go#L13-L49","documentation":"Thrown by BalancingRule.Build when a routing balancer rule's tag is an empty string. The balancer tag is the identifier that routing rules reference in their balancerTag field; an empty tag cannot be referenced, so the rule is rejected before selector/strategy validation. Selectors are checked next ('empty selector list'), so a rule reaching this error specifically failed the tag check.","triggerScenarios":"Declaring routing.balancers[] entry without a tag field, or with tag set to \"\".","commonSituations":"Hand-editing balancer lists and deleting the tag while keeping the entry; config generators emitting balancers without tags when no name was supplied.","solutions":["Give each balancer a unique non-empty tag, e.g. \"balancer0\"","Reference that exact tag from routing rules via balancerTag"],"exampleFix":"// before\n\"balancers\": [ { \"selector\": [\"out\"] } ]\n// after\n\"balancers\": [ { \"tag\": \"balancer0\", \"selector\": [\"out\"] } ]","handlingStrategy":"validation","validationCode":"for _, b := range routing.Balancers {\n\tif strings.TrimSpace(b.Tag) == \"\" {\n\t\treturn fmt.Errorf(\"balancer at index %d has an empty tag\", i)\n\t}\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Make balancer tag a required field in config schemas and templates","Cross-check that each routing rule's balancerTag matches a defined balancer tag"],"tags":["xray","config","routing","balancer","validation"],"backgroundTag":null,"analyzedSha":"7d214f8b094f75322fa3990f8aadad1c912f24f5","analyzedAt":"2026-08-15T14:26:24.325Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}