{"record":{"id":"b856294d07f3325b","repo":"grpc/grpc-java","slug":"unable-to-unpack-typedconfig-for-typedconfig","errorCode":null,"errorMessage":"Unable to unpack typedConfig for: \" + typedConfig.getTypeUrl()","messagePattern":"Unable to unpack typedConfig for: \" \\+ typedConfig\\.getTypeUrl\\(\\)","errorType":"validation","errorClass":"ResourceInvalidException","httpStatus":null,"severity":"error","filePath":"xds/src/main/java/io/grpc/xds/LoadBalancerConfigFactory.java","lineNumber":252,"sourceCode":"            serviceConfig = convertRoundRobinConfig();\n          } else if (typedConfig.is(LeastRequest.class)) {\n            serviceConfig = convertLeastRequestConfig(typedConfig.unpack(LeastRequest.class));\n          } else if (typedConfig.is(ClientSideWeightedRoundRobin.class)) {\n            serviceConfig = convertWeightedRoundRobinConfig(\n                typedConfig.unpack(ClientSideWeightedRoundRobin.class));\n          } else if (typedConfig.is(PickFirst.class)) {\n            serviceConfig = convertPickFirstConfig(typedConfig.unpack(PickFirst.class));\n          } else if (typedConfig.is(com.github.xds.type.v3.TypedStruct.class)) {\n            serviceConfig = convertCustomConfig(\n                typedConfig.unpack(com.github.xds.type.v3.TypedStruct.class));\n          } else if (typedConfig.is(com.github.udpa.udpa.type.v1.TypedStruct.class)) {\n            serviceConfig = convertCustomConfig(\n                typedConfig.unpack(com.github.udpa.udpa.type.v1.TypedStruct.class));\n          }\n\n          // TODO: support least_request once it is added to the envoy protos.\n        } catch (InvalidProtocolBufferException e) {\n          throw new ResourceInvalidException(\n              \"Unable to unpack typedConfig for: \" + typedConfig.getTypeUrl(), e);\n        }\n        // The service config is expected to have a single root entry, where the name of that entry\n        // is the name of the policy. A Load balancer with this name must exist in the registry.\n        if (serviceConfig == null || LoadBalancerRegistry.getDefaultRegistry()\n            .getProvider(Iterables.getOnlyElement(serviceConfig.keySet())) == null) {\n          logger.log(XdsLogLevel.WARNING, \"Policy {0} not found in the LB registry, skipping\",\n              typedConfig.getTypeUrl());\n          continue;\n        } else {\n          return serviceConfig;\n        }\n      }\n\n      // If we could not find a Policy that we could both convert as well as find a provider for\n      // then we have an invalid LB policy configuration.\n      throw new ResourceInvalidException(\"Invalid LoadBalancingPolicy: \" + loadBalancingPolicy);\n    }","sourceCodeStart":234,"sourceCodeEnd":270,"githubUrl":"https://github.com/grpc/grpc-java/blob/64daddc1f3d1975670f769f3e97bde8b2ba32d25/xds/src/main/java/io/grpc/xds/LoadBalancerConfigFactory.java#L234-L270","documentation":"ResourceInvalidException thrown when the Any typed_config inside an LB policy extension cannot be unpacked (InvalidProtocolBufferException), i.e. the bytes don't decode into the expected Envoy/UDPA struct proto (TypedStruct, Struct, or the specific policy config type). The typeUrl advertised by the config doesn't match its actual payload.","triggerScenarios":"convertToServiceConfig (called from convertWrrLocalityConfig) encounters a typed extension config whose typedConfig.getTypeUrl() content fails unpack() for every supported message type.","commonSituations":"Control plane sets a wrong @type annotation in a TypedStruct JSON config; mismatched proto versions between management server and grpc-xds; corrupted or hand-assembled Any payloads.","solutions":["Fix the @type / type_url in the LB policy typed config on the control plane so it matches the actual message type","Ensure the management server and grpc-java agree on supported extension config proto versions (upgrade one side)","Log and inspect the offending resource; compare its typeUrl with the types grpc-xds supports","Validate the config JSON with protoc/envoy validation before publishing to ADS"],"exampleFix":"// before: wrong @type in TypedStruct JSON\n{\"@type\": \"type.googleapis.com/wrong.pkg.Policy\", ...}\n// after\n{\"@type\": \"type.googleapis.com/envoy.extensions.lb.policies.round_robin.v3.RoundRobin\", ...}","handlingStrategy":"validation","validationCode":"// check typeUrl before accepting the extension config\nString url = typedConfig.getTypeUrl();\nboolean supported = url.endsWith(\"TypedStruct\") || url.endsWith(\"Struct\")\n    || url.endsWith(\"RingHash\") || url.endsWith(\"RoundRobin\");\nif (!supported) {\n  throw new IllegalArgumentException(\"Unsupported LB extension typeUrl: \" + url);\n}","typeGuard":null,"tryCatchPattern":"try {\n  /* apply xDS cluster config */;\n} catch (ResourceInvalidException e) {\n  if (e.getMessage().startsWith(\"Unable to unpack typedConfig\")) {\n    logger.log(Level.WARNING, \"Bad typed config from control plane: \" + e.getMessage(), e);\n    // reject resource; xDS will retry with a corrected one\n  } else { throw e; }\n}","preventionTips":["Ensure @type annotations in TypedStruct JSON match the real proto type","Keep management-server protos and grpc-java protos version-aligned","Use envoy validate / protoc to lint configs before publishing","Never assemble Any payloads by hand"],"tags":["xds","protobuf","config-parsing","typed-config"],"backgroundTag":"protobuf-unmarshal-failed","analyzedSha":"64daddc1f3d1975670f769f3e97bde8b2ba32d25","analyzedAt":"2026-09-08T06:14:57.704Z","contentChangedAt":"2026-09-08T06:14:57.704Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}