XTLS/Xray-core · error
unsupported router implementation
Error message
unsupported router implementation
What it means
The gRPC OverrideBalancerTarget handler type-asserts the registered router to routing.BalancerOverrider. Only the real app/router Router (or a custom implementation providing SetOverrideTarget/GetOverrideTarget/GetPrincipleTarget) satisfies it; anything else gets this error. It signals an environment/wiring problem, not a user-input problem.
Source
Thrown at app/router/command/command.go:53
if pt, ok := s.router.(routing.BalancerPrincipleTarget); ok {
{
res, err := pt.GetPrincipleTarget(request.GetTag())
if err != nil {
errors.LogInfoInner(ctx, err, "unable to obtain principle target")
} else {
ret.Balancer.PrincipleTarget = &PrincipleTargetInfo{Tag: res}
}
}
}
return &ret, nil
}
func (s *routingServer) OverrideBalancerTarget(ctx context.Context, request *OverrideBalancerTargetRequest) (*OverrideBalancerTargetResponse, error) {
if bo, ok := s.router.(routing.BalancerOverrider); ok {
return &OverrideBalancerTargetResponse{}, bo.SetOverrideTarget(request.BalancerTag, request.Target)
}
return nil, errors.New("unsupported router implementation")
}
func (s *routingServer) AddRule(ctx context.Context, request *AddRuleRequest) (*AddRuleResponse, error) {
if bo, ok := s.router.(routing.Router); ok {
return &AddRuleResponse{}, bo.AddRule(request.Config, request.ShouldAppend)
}
return nil, errors.New("unsupported router implementation")
}
func (s *routingServer) RemoveRule(ctx context.Context, request *RemoveRuleRequest) (*RemoveRuleResponse, error) {
if bo, ok := s.router.(routing.Router); ok {
return &RemoveRuleResponse{}, bo.RemoveRule(request.RuleTag)
}
return nil, errors.New("unsupported router implementation")
}
func (s *routingServer) ListRule(ctx context.Context, request *ListRuleRequest) (*ListRuleResponse, error) {
if bo, ok := s.router.(routing.Router); ok {View on GitHub (pinned to 7d214f8b09)
Solutions
- Register the standard app/router instance as the handler for routing.RoutingService
- If using a custom router, implement SetOverrideTarget/GetOverrideTarget/GetPrincipleTarget on it
- Align versions of xray-core packages so command and router come from the same release
Example fix
// before command.NewRoutingServer(mockRouter, nil) // mock lacks BalancerOverrider // after command.NewRoutingServer(realRouter, routingStats) // app/router.Router implements it
Defensive patterns
Strategy: type-guard
Type guard
func supportsOverride(r interface{}) bool {
_, ok := r.(routing.BalancerOverrider)
return ok
} Prevention
- Wire command services against the real app/router instance in production
- Add compile-time assertion: var _ routing.BalancerOverrider = (*router.Router)(nil)
- Run integration tests that exercise the gRPC surface, not just unit tests with mocks
When it happens
Trigger: RoutingService server constructed with a router implementation lacking the BalancerOverrider interface (mocks in tests, alternative router packages, older Router version).
Common situations: Unit tests injecting a fake router; forks that replaced the router; version mismatch where the command package is newer than the router implementation.
Related errors
- AddRule: config type error
- unable to get logger instance
- failed to close logger
- failed to start logger
- can't get inbound proxy from handler.
AI-assisted analysis of XTLS/Xray-core@7d214f8b09 (2026-08-15).
Data as JSON: /api/errors/c17c0d15afb19b79.
Report an issue: GitHub.