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

  1. List the configured balancers from the routing config and use the exact tag string in API calls.
  2. After renaming a balancer, update every external script/panel that references the old tag.
  3. 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

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


AI-assisted analysis of XTLS/Xray-core@7d214f8b09 (2026-08-15). Data as JSON: /api/errors/1a7038b238a54891. Report an issue: GitHub.