{"record":{"id":"f1e60f4e3c560005","repo":"XTLS/Xray-core","slug":"unable-to-select-outbounds","errorCode":null,"errorMessage":"unable to select outbounds","messagePattern":"unable to select outbounds","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"app/router/balancing.go","lineNumber":143,"sourceCode":"}\n\n// SelectOutbounds select outbounds with selectors of the Balancer\nfunc (b *Balancer) SelectOutbounds() ([]string, error) {\n\ths, ok := b.ohm.(outbound.HandlerSelector)\n\tif !ok {\n\t\treturn nil, errors.New(\"outbound.Manager is not a HandlerSelector\")\n\t}\n\ttags := hs.Select(b.selectors)\n\treturn tags, nil\n}\n\n// GetPrincipleTarget implements routing.BalancerPrincipleTarget\nfunc (r *Router) GetPrincipleTarget(tag string) ([]string, error) {\n\tif b, ok := r.balancers[tag]; ok {\n\t\tif s, ok := b.strategy.(BalancingPrincipleTarget); ok {\n\t\t\tcandidates, err := b.SelectOutbounds()\n\t\t\tif err != nil {\n\t\t\t\treturn nil, errors.New(\"unable to select outbounds\").Base(err)\n\t\t\t}\n\t\t\treturn s.GetPrincipleTarget(candidates), nil\n\t\t}\n\t\treturn nil, errors.New(\"unsupported GetPrincipleTarget\")\n\t}\n\treturn nil, errors.New(\"cannot find tag\")\n}\n\n// SetOverrideTarget implements routing.BalancerOverrider\nfunc (r *Router) SetOverrideTarget(tag, target string) error {\n\tif b, ok := r.balancers[tag]; ok {\n\t\tb.override.Put(target)\n\t\treturn nil\n\t}\n\treturn errors.New(\"cannot find tag\")\n}\n\n// GetOverrideTarget implements routing.BalancerOverrider","sourceCodeStart":125,"sourceCodeEnd":161,"githubUrl":"https://github.com/XTLS/Xray-core/blob/7d214f8b094f75322fa3990f8aadad1c912f24f5/app/router/balancing.go#L125-L161","documentation":"Router.GetPrincipleTarget failed to gather candidates: it calls b.SelectOutbounds() (which resolves the balancer's selectors through the outbound manager's HandlerSelector) and that returned an error, wrapped with this message. This is an API-surface error used by the stats/ observation layer to report which targets a balancer currently picks; it indicates the selector resolution layer is broken, not that balancing itself failed.","triggerScenarios":"Invoking the balancer principle-target query (e.g. via router API/command) for a balancer whose underlying outbound manager does not implement HandlerSelector, or whose Select() call errors — commonly the manager was constructed without selector support or outbound tags referenced by selectors disappeared.","commonSituations":"Management/observation tooling (api queries like QueryStats/ GetPrincipleTarget-based panels) hitting a router whose outbound manager lacks selector capability; configs where the balancer selector references non-existent tags after renames. The data path usually still works; only the query fails.","solutions":["Confirm the outbound manager in use supports selection (feature outbound.Manager with HandlerSelector); custom/embedded managers must implement it for this API.","Fix selector expressions so they match existing outbound tags.","If the observation query is optional, tolerate/skip the error rather than treating it as a connectivity failure."],"exampleFix":null,"handlingStrategy":"type-guard","validationCode":"// Capability probe before calling the API\nif _, ok := router.(routing.BalancerPrincipleTarget); !ok { skipPrincipleTargetQuery() }","typeGuard":"func supportsPrincipleTarget(r *router.Router, balancerTag string) bool {\n    b, ok := r.Balancer(balancerTag)\n    if !ok { return false }\n    _, ok = b.Strategy().(router.BalancingPrincipleTarget)\n    return ok\n}","tryCatchPattern":"if _, err := router.GetPrincipleTarget(tag); err != nil {\n    if strings.Contains(err.Error(), \"unable to select outbounds\") {\n        log.Warnf(\"observation degraded for balancer %s: %v\", tag, err) // data path unaffected\n        return nil\n    }\n    return err\n}","preventionTips":["Probe capability before calling observation APIs per balancer","Keep selector expressions in sync with existing outbound tags","Treat these query errors as observability-only; verify forwarding separately"],"tags":["go","xray","routing","balancer","api"],"backgroundTag":null,"analyzedSha":"7d214f8b094f75322fa3990f8aadad1c912f24f5","analyzedAt":"2026-08-15T14:26:24.325Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}