{"record":{"id":"48db52b356cd6e52","repo":"grpc/grpc-go","slug":"pickfirst-unable-to-unmarshal-lb-policy-config","errorCode":null,"errorMessage":"pickfirst: unable to unmarshal LB policy config: %s, error: %v","messagePattern":"pickfirst: unable to unmarshal LB policy config: (.+?), error: (.+?)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"balancer/pickfirst/pickfirst.go","lineNumber":125,"sourceCode":"\t\ttarget:          bo.Target.String(),\n\t\tmetricsRecorder: cc.MetricsRecorder(),\n\n\t\tsubConns:              resolver.NewAddressMapV2[*scData](),\n\t\tstate:                 connectivity.Connecting,\n\t\tcancelConnectionTimer: func() {},\n\t}\n\tb.logger = internalgrpclog.NewPrefixLogger(logger, fmt.Sprintf(logPrefix, b))\n\treturn b\n}\n\nfunc (b pickfirstBuilder) Name() string {\n\treturn Name\n}\n\nfunc (pickfirstBuilder) ParseConfig(js json.RawMessage) (serviceconfig.LoadBalancingConfig, error) {\n\tvar cfg pfConfig\n\tif err := json.Unmarshal(js, &cfg); err != nil {\n\t\treturn nil, fmt.Errorf(\"pickfirst: unable to unmarshal LB policy config: %s, error: %v\", string(js), err)\n\t}\n\treturn cfg, nil\n}\n\n// EnableHealthListener updates the state to configure pickfirst for using a\n// generic health listener.\n//\n// # Experimental\n//\n// Notice: This API is EXPERIMENTAL and may be changed or removed in a later\n// release.\nfunc EnableHealthListener(state resolver.State) resolver.State {\n\tstate.Attributes = state.Attributes.WithValue(enableHealthListenerKeyType{}, true)\n\treturn state\n}\n\ntype pfConfig struct {\n\tserviceconfig.LoadBalancingConfig `json:\"-\"`","sourceCodeStart":107,"sourceCodeEnd":143,"githubUrl":"https://github.com/grpc/grpc-go/blob/03255a9237b6eb32710f6bc4f2de9a675b99fe36/balancer/pickfirst/pickfirst.go#L107-L143","documentation":"Raised by pickfirst's ParseConfig when the JSON service config for the pick_first policy cannot be unmarshalled into pfConfig. Unlike least-request (error 96), this message ALSO echoes the raw offending config string (%s) alongside the json error (%v), making it easy to see exactly what bytes failed. The channel rejects the config and falls back.","triggerScenarios":"The service config contains a pick_first block whose JSON is malformed or whose fields have wrong types. pfConfig currently only accepts the boolean shuffleAddressList; any other shape fails. json.Unmarshal fails and the error includes the raw input.","commonSituations":"Sending shuffleAddressList as a string \"true\" instead of boolean true; adding an unsupported field to pick_first's config; a malformed JSON payload from a config-discovery service; version skew where a newer field is sent to an older client.","solutions":["Inspect the echoed raw config in %s and the json error in %v to pinpoint the bad token.","Ensure shuffleAddressList is a JSON boolean, and remove any other fields not in pfConfig.","Validate the service config JSON with `jq` and against the gRPC service config schema.","Upgrade grpc-go if the config uses a field added in a newer version."],"exampleFix":"// before (shuffleAddressList as string):\n{ \"loadBalancingConfig\": { \"pick_first\": { \"shuffleAddressList\": \"true\" } } }\n\n// after:\n{ \"loadBalancingConfig\": { \"pick_first\": { \"shuffleAddressList\": true } } }","handlingStrategy":"validation","validationCode":"type pfCfg struct {\n    ShuffleAddressList bool `json:\"shuffleAddressList\"`\n}\nfunc validatePickFirstConfig(raw json.RawMessage) error {\n    var c pfCfg\n    dec := json.NewDecoder(bytes.NewReader(raw))\n    dec.DisallowUnknownFields()\n    if err := dec.Decode(&c); err != nil {\n        return fmt.Errorf(\"pickfirst: unable to unmarshal LB policy config: %s, error: %v\", string(raw), err)\n    }\n    return nil\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Use DisallowUnknownFields to catch stray pick_first config fields.","Ensure shuffleAddressList is a JSON boolean.","Validate the full service config JSON with `jq`.","Upgrade grpc-go to match the config schema version."],"tags":["balancer","pickfirst","service-config","json","config"],"analyzedSha":"03255a9237b6eb32710f6bc4f2de9a675b99fe36","analyzedAt":"2026-08-07T00:29:34.215Z","schemaVersion":2},"datasetVersion":"2026-08-07T03:17:09.362Z"}