{"record":{"id":"f89cb6c2ab8f8e3f","repo":"grpc/grpc-go","slug":"xds-node-id-s-w","errorCode":null,"errorMessage":"[xDS node id: %s]: %w","messagePattern":"\\[xDS node id: (.+?)\\]: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/xds/resolver/serviceconfig.go","lineNumber":174,"sourceCode":"\tsendNewServiceConfig func() // Function to send a new service config to gRPC.\n\n\t// Configuration received from the xDS management server.\n\tvirtualHost      virtualHost\n\troutes           []route\n\tclusters         map[string]*clusterInfo\n\tplugins          map[string]*clusterInfo\n\thttpFilterConfig []xdsresource.HTTPFilter\n\txdsConfig        *xdsresource.XDSConfig\n}\n\nvar errNoMatchedRouteFound = status.Errorf(codes.Unavailable, \"no matched route was found\")\nvar errUnsupportedClientRouteAction = status.Errorf(codes.Unavailable, \"matched route does not have a supported route action type\")\n\n// annotateErrorWithNodeID annotates the given error with the provided xDS node\n// ID. This is used by the real config selector when it runs into errors, and\n// also by the erroring config selector.\nfunc annotateErrorWithNodeID(err error, nodeID string) error {\n\treturn fmt.Errorf(\"[xDS node id: %s]: %w\", nodeID, err)\n}\n\nfunc (cs *configSelector) SelectConfig(rpcInfo iresolver.RPCInfo) (*iresolver.RPCConfig, error) {\n\tvar rt *route\n\tmd, _ := metadata.FromOutgoingContext(rpcInfo.Context)\n\tif extraMD, ok := grpcutil.ExtraMetadata(rpcInfo.Context); ok {\n\t\tmd = metadata.Join(md, extraMD)\n\t\t// Remove all binary headers. They are hard to match with. May need\n\t\t// to add back if asked by users.\n\t\tfor k := range md {\n\t\t\tif strings.HasSuffix(k, \"-bin\") {\n\t\t\t\tdelete(md, k)\n\t\t\t}\n\t\t}\n\t}\n\t// Loop through routes in order and select first match.\n\tfor _, r := range cs.routes {\n\t\tif r.m.Match(rpcInfo.Method, md) {","sourceCodeStart":156,"sourceCodeEnd":192,"githubUrl":"https://github.com/grpc/grpc-go/blob/03255a9237b6eb32710f6bc4f2de9a675b99fe36/internal/xds/resolver/serviceconfig.go#L156-L192","documentation":"This is an error annotation wrapper produced by the xDS resolver's config selector (annotateErrorWithNodeID, serviceconfig.go:173). It wraps RPC routing failures with the xDS node ID so you can correlate the failure with the specific xDS-managed channel. It is returned (not panicked) when an RPC cannot be matched to a route or the selected cluster cannot be resolved against the current xDS configuration. The wrapped error is normally a codes.Unavailable status.","triggerScenarios":"An RPC is invoked on an xDS-configured gRPC channel and configSelector.SelectConfig (serviceconfig.go:177) fails: (1) the method/path matches no route in the LDS/RDS config -> errNoMatchedRouteFound; (2) the matched route's action is not RouteActionRoute -> errUnsupportedClientRouteAction; (3) the resolved cluster object is not a *routeCluster. Additionally, when the channel is in a broken xDS state, newErroringConfigSelector wraps EVERY outgoing RPC with this annotation.","commonSituations":"The xDS control plane (Traffic Director, Istio, Envoy xDS server) has not delivered a Listener/Route config covering the service/method being called. A new gRPC method path was added in code but not added to the route match rules. The node ID in the bootstrap config does not match what the control plane expects, so no config is ever sent. A transient xDS update left zero valid routes.","solutions":["Inspect the full wrapped error to see the underlying cause (no matched route / unsupported action / cluster error) and note the xDS node ID.","Confirm the called method path (/package.Service/Method) is covered by a route match rule (or a catch-all prefix) in the xDS route configuration.","Dump the received xDS config (enable CSDS / xDS resource logging) and verify virtualHost routes and clusters are present for that node ID.","Verify the xDS node ID in your bootstrap JSON matches the identity the control plane is configuring; fix and restart the client if mismatched.","If transient, the channel will retry on the next xDS config update; use a connectivity-state or ready-check before issuing the RPC."],"exampleFix":"// before: RPC fails because no route matches the method path\nresp, err := conn.Invoke(ctx, \"/myapp.Billing/Charge\", req, out)\n// err = rpc error: code = Unavailable desc = [xDS node id: node-1]: no matched route was found\n\n// after: ensure the control-plane route config includes the method path,\n// or use a catch-all prefix route, then retry the RPC.\n// Route match in xDS: { prefix: \"/myapp.Billing/\" -> cluster: billing-cluster }","handlingStrategy":"try-catch","validationCode":"// Before invoking, check channel readiness on an xDS channel\nif conn.GetState() != connectivity.Ready {\n    // wait for ready or surface a clearer error before the RPC\n}\n// Optionally inspect the latest service config via CSDS/admin to confirm\n// the method path is routed before issuing the RPC.","typeGuard":null,"tryCatchPattern":"// Inspect the returned status from the RPC\nresp, err := conn.Invoke(ctx, \"/pkg.Svc/Method\", req, out)\nif err != nil {\n    st, _ := status.FromError(err)\n    if st.Code() == codes.Unavailable && strings.Contains(st.Message(), \"[xDS node id:\") {\n        // xDS routing/config problem: log node id + underlying msg,\n        // surface as config error, optionally retry after xDS refresh\n    }\n    return err\n}","preventionTips":["Keep xDS route configuration in sync with deployed gRPC method paths; add new methods to route rules before deploying callers.","Verify the xDS node ID in bootstrap matches the control plane's expected identity.","Use a connectivity-state gate or readiness probe before sending traffic to an xDS channel."],"tags":["xds","routing","config-selection","grpc-go"],"analyzedSha":"03255a9237b6eb32710f6bc4f2de9a675b99fe36","analyzedAt":"2026-08-07T00:29:34.215Z","schemaVersion":2},"datasetVersion":"2026-08-07T03:17:09.362Z"}