XTLS/Xray-core · error
cannot find tag
Error message
cannot find tag
What it means
Generic lookup miss in the router's balancer map: GetPrincipleTarget, SetOverrideTarget, and GetOverrideTarget all return this when the tag argument names no registered balancer. It is purely a 'no such balancer' error — the tag exists neither in r.balancers (built from routing config) nor anywhere the API accepts.
Source
Thrown at app/router/balancing.go:149
return nil, errors.New("outbound.Manager is not a HandlerSelector")
}
tags := hs.Select(b.selectors)
return tags, nil
}
// GetPrincipleTarget implements routing.BalancerPrincipleTarget
func (r *Router) GetPrincipleTarget(tag string) ([]string, error) {
if b, ok := r.balancers[tag]; ok {
if s, ok := b.strategy.(BalancingPrincipleTarget); ok {
candidates, err := b.SelectOutbounds()
if err != nil {
return nil, errors.New("unable to select outbounds").Base(err)
}
return s.GetPrincipleTarget(candidates), nil
}
return nil, errors.New("unsupported GetPrincipleTarget")
}
return nil, errors.New("cannot find tag")
}
// SetOverrideTarget implements routing.BalancerOverrider
func (r *Router) SetOverrideTarget(tag, target string) error {
if b, ok := r.balancers[tag]; ok {
b.override.Put(target)
return nil
}
return errors.New("cannot find tag")
}
// GetOverrideTarget implements routing.BalancerOverrider
func (r *Router) GetOverrideTarget(tag string) (string, error) {
if b, ok := r.balancers[tag]; ok {
return b.override.Get(), nil
}
return "", errors.New("cannot find tag")
}View on GitHub (pinned to 7d214f8b09)
Solutions
- List the configured balancers from the routing config and use the exact tag string in API calls.
- After renaming a balancer, update every external script/panel that references the old tag.
- If the error appears right after startup, retry once the instance reports the router feature ready.
Example fix
// before (api call)
router.SetOverrideTarget("bl", "node-2") // no balancer tagged "bl"
// after
router.SetOverrideTarget("bal", "node-2") // matches { "balancers": [ { "tag": "bal", ... } ] } Defensive patterns
Strategy: validation
Validate before calling
// Verify the balancer tag against routing config before API calls
tags := map[string]bool{}
for _, b := range cfg.Routing.Balancers { tags[b.Tag] = true }
if !tags[queryTag] { return fmt.Errorf("unknown balancer tag %q", queryTag) } Type guard
func isKnownBalancerTag(cfg RoutingConfig, tag string) bool {
for _, b := range cfg.Balancers { if b.Tag == tag { return true } }
return false
} Try / catch
if err := router.SetOverrideTarget(tag, target); err != nil {
if strings.Contains(err.Error(), "cannot find tag") {
return fmt.Errorf("balancer %q not in configured routing balancers; check spelling", tag)
}
return err
} Prevention
- Drive admin tooling from the live config, not hardcoded tag strings
- Update scripts/panels after any balancer rename
- Retry once after startup completes to rule out initialization races
When it happens
Trigger: Calling router balancer override/inspection APIs with a misspelled or unconfigured balancerTag — e.g. the API command SetOverrideTarget("bl", ...) when the routing config defines balancer tag "bal", or querying before routing/balancers finished initializing.
Common situations: Automation scripts or admin panels guessing balancer tags; renames in routing config breaking external tooling that hardcodes the old tag; API calls racing instance startup before the router feature registers balancers.
Related errors
- unable to select outbounds
- unsupported GetPrincipleTarget
- balancing strategy returns empty tag
- can't get inbound proxy from handler.
- proxy is not a UserManager
AI-assisted analysis of XTLS/Xray-core@7d214f8b09 (2026-08-15).
Data as JSON: /api/errors/1a7038b238a54891.
Report an issue: GitHub.