{"record":{"id":"3ea577954e9b6415","repo":"grpc/grpc-go","slug":"invalid-loadbalancingconfig-no-supported-policies","errorCode":null,"errorMessage":"invalid loadBalancingConfig: no supported policies found in %v","messagePattern":"invalid loadBalancingConfig: no supported policies found in (.+?)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/serviceconfig/serviceconfig.go","lineNumber":125,"sourceCode":"\t\t\tif string(jsonCfg) != \"{}\" {\n\t\t\t\tlogger.Warningf(\"non-empty balancer configuration %q, but balancer does not implement ParseConfig\", string(jsonCfg))\n\t\t\t}\n\t\t\t// Stop at this, though the builder doesn't support parsing config.\n\t\t\treturn nil\n\t\t}\n\n\t\tcfg, err := parser.ParseConfig(jsonCfg)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"error parsing loadBalancingConfig for policy %q: %v\", name, err)\n\t\t}\n\t\tbc.Config = cfg\n\t\treturn nil\n\t}\n\t// This is reached when the for loop iterates over all entries, but didn't\n\t// return. This means we had a loadBalancingConfig slice but did not\n\t// encounter a registered policy. The config is considered invalid in this\n\t// case.\n\treturn fmt.Errorf(\"invalid loadBalancingConfig: no supported policies found in %v\", names)\n}\n\n// MethodConfig defines the configuration recommended by the service providers for a\n// particular method.\ntype MethodConfig struct {\n\t// WaitForReady indicates whether RPCs sent to this method should wait until\n\t// the connection is ready by default (!failfast). The value specified via the\n\t// gRPC client API will override the value set here.\n\tWaitForReady *bool\n\t// Timeout is the default timeout for RPCs sent to this method. The actual\n\t// deadline used will be the minimum of the value specified here and the value\n\t// set by the application via the gRPC client API.  If either one is not set,\n\t// then the other will be used.  If neither is set, then the RPC has no deadline.\n\tTimeout *time.Duration\n\t// MaxReqSize is the maximum allowed payload size for an individual request in a\n\t// stream (client->server) in bytes. The size which is measured is the serialized\n\t// payload after per-message compression (but before stream compression) in bytes.\n\t// The actual value used is the minimum of the value specified here and the value set","sourceCodeStart":107,"sourceCodeEnd":143,"githubUrl":"https://github.com/grpc/grpc-go/blob/03255a9237b6eb32710f6bc4f2de9a675b99fe36/internal/serviceconfig/serviceconfig.go#L107-L143","documentation":"This error occurs when the loadBalancingConfig array in a service config was iterated completely, but none of the listed policy names matched a registered balancer. gRPC treats this as an invalid config because it cannot select any load balancing policy to use.","triggerScenarios":"A service config lists only balancer names that are not registered in the running gRPC process, e.g., only \"grpclb\" when the grpclb balancer was never imported/registered, or only custom policy names not linked into the binary.","commonSituations":"Using a gRPC build that doesn't include a required balancer (e.g., xds/rls not imported), version skew between control plane and client, or migrating to a new balancer name before the client supports it.","solutions":["Ensure at least one listed policy is registered: import the balancer package (e.g., _ \"google.golang.org/grpc/balancer/roundrobin\") so its init() registers it.","Add a well-known fallback policy (e.g., \"pick_first\" or \"round_robin\") to the loadBalancingConfig array so the client always finds a supported one.","Verify the policy name spelling matches the registered name exactly (case-sensitive)."],"exampleFix":"// before (broken): only an unregistered policy is listed\n\"loadBalancingConfig\": [{\"custom_lb\": {}}]\n\n// after (valid): add a registered fallback\n\"loadBalancingConfig\": [{\"custom_lb\": {}}, {\"round_robin\": {}}]","handlingStrategy":"validation","validationCode":"// Check that at least one listed policy is registered before applying config\nfunc hasRegisteredBalancer(raw []byte) bool {\n    var entries []map[string]json.RawMessage\n    if json.Unmarshal(raw, &entries) != nil { return false }\n    for _, e := range entries {\n        for name := range e {\n            if balancer.Get(name) != nil { return true }\n        }\n    }\n    return false\n}","typeGuard":null,"tryCatchPattern":"var bc serviceconfig.BalancerConfig\nif err := json.Unmarshal(raw, &bc); err != nil {\n    if strings.Contains(err.Error(), \"no supported policies found\") {\n        // ensure required balancers are imported\n        _ = balancer.Get // force check\n    }\n}","preventionTips":["Always import balancer packages (blank import) for policies referenced in service config.","Include a standard fallback policy (round_robin, pick_first) in every loadBalancingConfig.","Run integration tests that verify service config application with the production binary."],"tags":["service-config","load-balancing","balancer","registration","configuration"],"analyzedSha":"03255a9237b6eb32710f6bc4f2de9a675b99fe36","analyzedAt":"2026-08-07T00:29:34.215Z","schemaVersion":2},"datasetVersion":"2026-08-07T03:17:09.362Z"}