{"record":{"id":"d2410ca77bfbc5a9","repo":"grpc/grpc-go","slug":"xds-unable-to-unmarshal-lbconfig-s-error-v-d2410c","errorCode":null,"errorMessage":"xds: unable to unmarshal LBconfig: %s, error: %v","messagePattern":"xds: unable to unmarshal LBconfig: (.+?), error: (.+?)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/xds/balancer/outlierdetection/balancer.go","lineNumber":112,"sourceCode":"\tb.logger.Infof(\"Created\")\n\tb.child = synchronizingBalancerWrapper{lb: gracefulswitch.NewBalancer(b, bOpts)}\n\tgo b.run()\n\treturn b\n}\n\nfunc (bb) ParseConfig(s json.RawMessage) (serviceconfig.LoadBalancingConfig, error) {\n\tlbCfg := &LBConfig{\n\t\t// Default top layer values as documented in A50.\n\t\tInterval:           iserviceconfig.Duration(10 * time.Second),\n\t\tBaseEjectionTime:   iserviceconfig.Duration(30 * time.Second),\n\t\tMaxEjectionTime:    iserviceconfig.Duration(300 * time.Second),\n\t\tMaxEjectionPercent: 10,\n\t}\n\n\t// This unmarshalling handles underlying layers sre and fpe which have their\n\t// own defaults for their fields if either sre or fpe are present.\n\tif err := json.Unmarshal(s, lbCfg); err != nil { // Validates child config if present as well.\n\t\treturn nil, fmt.Errorf(\"xds: unable to unmarshal LBconfig: %s, error: %v\", string(s), err)\n\t}\n\n\t// Note: in the xds flow, these validations will never fail. The xdsclient\n\t// performs the same validations as here on the xds Outlier Detection\n\t// resource before parsing resource into JSON which this function gets\n\t// called with. A50 defines two separate places for these validations to\n\t// take place, the xdsclient and this ParseConfig method. \"When parsing a\n\t// config from JSON, if any of these requirements is violated, that should\n\t// be treated as a parsing error.\" - A50\n\tswitch {\n\t// \"The google.protobuf.Duration fields interval, base_ejection_time, and\n\t// max_ejection_time must obey the restrictions in the\n\t// google.protobuf.Duration documentation and they must have non-negative\n\t// values.\" - A50\n\t// Approximately 290 years is the maximum time that time.Duration (int64)\n\t// can represent. The restrictions on the protobuf.Duration field are to be\n\t// within +-10000 years. Thus, just check for negative values.\n\tcase lbCfg.Interval < 0:","sourceCodeStart":94,"sourceCodeEnd":130,"githubUrl":"https://github.com/grpc/grpc-go/blob/0c51461d27177d997e14c642fe18c11668fc09a3/internal/xds/balancer/outlierdetection/balancer.go#L94-L130","documentation":"ParseConfig for outlier_detection json.Unmarshal's the raw bytes into *LBConfig (balancer.go:111-113). If unmarshal fails (malformed JSON, wrong field types, invalid duration string, unknown enum), parsing is aborted and the original bytes plus error are returned.","triggerScenarios":"raw JSON is syntactically invalid, contains fields with wrong types (e.g. interval as a non-duration string), or has structurally incompatible nested objects (child policy config of wrong shape).","commonSituations":"Manually constructed outlier_detection JSON with typos; control plane sending malformed config (xdsclient should catch this upstream, so this is rare in production); test fixtures with bad JSON; field type drift after a gRPC upgrade.","solutions":["Validate the raw JSON with a JSON parser before calling ParseConfig.","Cross-check field types against the LBConfig struct (Interval is a duration string, percentages are uint32).","For xDS deployments, investigate why xdsclient let the malformed resource through."],"exampleFix":"// before\nrawJSON := []byte(`{\"interval\": \"not-a-duration\"}`)\ncfg, err := outlierdetection.ParseConfig(rawJSON) // errors\n// after\nrawJSON := []byte(`{\"interval\": \"10s\"}`)\ncfg, err := outlierdetection.ParseConfig(rawJSON)","handlingStrategy":"validation","validationCode":"// Validate raw JSON before calling ParseConfig.\nfunc validateOutlierDetectionJSON(raw json.RawMessage) error {\n    var probe map[string]json.RawMessage\n    if err := json.Unmarshal(raw, &probe); err != nil {\n        return fmt.Errorf(\"outlier_detection config is not valid JSON: %w\", err)\n    }\n    return nil\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Schema-validate the outlier_detection JSON before passing it to ParseConfig.","Use the A50 defaults so only fields you intentionally override are present.","For xDS deployments, monitor NACKs which indicate the xdsclient failed to validate upstream."],"tags":["go","grpc","xds","balancer","json","outlier-detection"],"backgroundTag":null,"analyzedSha":"0c51461d27177d997e14c642fe18c11668fc09a3","analyzedAt":"2026-08-11T14:49:15.055Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}