{"record":{"id":"bd23a8253c481dcd","repo":"XTLS/Xray-core","slug":"invalid-routing-request","errorCode":null,"errorMessage":"Invalid routing request.","messagePattern":"Invalid routing request\\.","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"app/router/command/command.go","lineNumber":94,"sourceCode":"\t\t\t\tRuleTag: v.GetRuleTag(),\n\t\t\t})\n\t\t}\n\t\treturn response, nil\n\t}\n\treturn nil, errors.New(\"unsupported router implementation\")\n}\n\n// NewRoutingServer creates a statistics service with statistics manager.\nfunc NewRoutingServer(router routing.Router, routingStats stats.Channel) RoutingServiceServer {\n\treturn &routingServer{\n\t\trouter:       router,\n\t\troutingStats: routingStats,\n\t}\n}\n\nfunc (s *routingServer) TestRoute(ctx context.Context, request *TestRouteRequest) (*RoutingContext, error) {\n\tif request.RoutingContext == nil {\n\t\treturn nil, errors.New(\"Invalid routing request.\")\n\t}\n\troute, err := s.router.PickRoute(AsRoutingContext(request.RoutingContext))\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tif request.PublishResult && s.routingStats != nil {\n\t\tctx, _ := context.WithTimeout(context.Background(), 4*time.Second)\n\t\ts.routingStats.Publish(ctx, route)\n\t}\n\treturn AsProtobufMessage(request.FieldSelectors)(route), nil\n}\n\nfunc (s *routingServer) SubscribeRoutingStats(request *SubscribeRoutingStatsRequest, stream RoutingService_SubscribeRoutingStatsServer) error {\n\tif s.routingStats == nil {\n\t\treturn errors.New(\"Routing statistics not enabled.\")\n\t}\n\tgenMessage := AsProtobufMessage(request.FieldSelectors)\n\tsubscriber, err := stats.SubscribeRunnableChannel(s.routingStats)","sourceCodeStart":76,"sourceCodeEnd":112,"githubUrl":"https://github.com/XTLS/Xray-core/blob/7d214f8b094f75322fa3990f8aadad1c912f24f5/app/router/command/command.go#L76-L112","documentation":"TestRoute immediately rejects requests whose RoutingContext field is nil, since there is nothing to route. It is pure request validation occurring before PickRoute is invoked.","triggerScenarios":"Sending TestRouteRequest with RoutingContext unset (default nil in protobuf), e.g. building the request struct without populating the field.","commonSituations":"Client code constructing TestRouteRequest{} and forgetting the nested message; decoding failures silently yielding nil; schema changes where the field was renamed.","solutions":["Populate request.RoutingContext with at least the required fields (target/network) before calling TestRoute","Add a nil check client-side to return a clearer local error","Validate the protobuf marshaling/unmarshaling path if the field should have been set"],"exampleFix":"// before\nreq := &command.TestRouteRequest{PublishResult: true}\nresp, err := client.TestRoute(ctx, req) // Invalid routing request.\n\n// after\nreq := &command.TestRouteRequest{\n    RoutingContext: &router.RoutingContext{\n        Target: &net.IPOrDomain{Domain: \"example.com\"},\n        Network: net.Network_TCP,\n    },\n}","handlingStrategy":"validation","validationCode":"if req.RoutingContext == nil {\n    return fmt.Errorf(\"RoutingContext is required for TestRoute\")\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Always populate RoutingContext (at minimum Target and Network)","Wrap gRPC clients with request builders that enforce required fields","Log the full request on failure to spot unset nested messages"],"tags":["routing","grpc","validation","test-route"],"backgroundTag":null,"analyzedSha":"7d214f8b094f75322fa3990f8aadad1c912f24f5","analyzedAt":"2026-08-15T14:26:24.325Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}