{"record":{"id":"640cf38e2334bac7","repo":"cilium/cilium","slug":"parse-resource-w-640cf3","errorCode":null,"errorMessage":"parse resource: %w","messagePattern":"parse resource: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/xds/experimental/client/client_sotw.go","lineNumber":56,"sourceCode":"\tfor i := range curr.VersionedResources {\n\t\treqResourceNames.Insert(curr.VersionedResources[i].Name)\n\t}\n\treqResourceNames.Insert(obsReq.resourceNames...)\n\n\treturn &discoverypb.DiscoveryRequest{\n\t\tNode:          node,\n\t\tTypeUrl:       obsReq.typeUrl,\n\t\tResourceNames: slices.Collect(maps.Keys(reqResourceNames)),\n\t}\n}\n\nfunc (sotw *sotw) tx(resp *discoverypb.DiscoveryResponse, get getter) (txs, error) {\n\ttypeUrl := resp.GetTypeUrl()\n\tupsertedResources := make(nameToResource)\n\tfor _, res := range resp.GetResources() {\n\t\tmsg, name, err := parseResource(typeUrl, res)\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"parse resource: %w\", err)\n\t\t}\n\t\tupsertedResources[name] = msg\n\t}\n\n\tvar deletedResources []string\n\tif typeUrl == envoy.ListenerTypeURL || typeUrl == envoy.ClusterTypeURL {\n\t\tdeletedResources = findMissing(typeUrl, upsertedResources, get)\n\t}\n\ttransactions := txs{{typeUrl: typeUrl, updated: upsertedResources, deleted: deletedResources}}\n\n\tif typeUrl == envoy.ClusterTypeURL {\n\t\tdeletedResources := findMissing(envoy.EndpointTypeURL, upsertedResources, get)\n\t\ttransactions = append(transactions, tx{typeUrl: envoy.EndpointTypeURL, deleted: deletedResources})\n\t}\n\treturn transactions, nil\n}\n\nfunc findMissing(typeUrl string, curr nameToResource, get getter) []string {","sourceCodeStart":38,"sourceCodeEnd":74,"githubUrl":"https://github.com/cilium/cilium/blob/ac7b90affa4baf0642e6685319d56907b3a73a6d/pkg/xds/experimental/client/client_sotw.go#L38-L74","documentation":"The xDS state-of-the-world client fails to parse one resource in a DiscoveryResponse while processing it in tx(). This is a wrapper around a lower-level parseResource failure (typeUrl mismatch, unmarshal error, unhandled type, or missing name); the original cause is attached via %w. The whole batch of upserted resources is discarded when any single resource fails to parse.","triggerScenarios":"The xDS management server sends a DiscoveryResponse containing an Any resource whose type_url does not match the response's type_url, whose payload cannot be unmarshaled into the expected proto message, whose type is not Listener/Cluster/ClusterLoadAssignment/RouteConfiguration, or whose extracted name is empty.","commonSituations":"A misbehaving or buggy control plane (custom istiod, third-party xDS server) sends mixed or malformed resources; envoy-proxy protocol version drift means an unexpected resource type arrives; a resource in the registry has an empty name (e.g. a Cluster created without a name).","solutions":["Inspect the wrapped cause (%w) in the error chain to identify which of the four parseResource failures occurred","Verify the DiscoveryResponse type_url matches every resource's Any.type_url sent by the management server","Log and inspect the offending resource (name/type_url) on the server side and fix or remove it","If a custom resource type is being sent, add a case for it in parseResource's type switch"],"exampleFix":"// before: server sends resources without setting type_url on each Any\nresp := &discoverypb.DiscoveryResponse{TypeUrl: envoy.ClusterTypeURL, Resources: []*anypb.Any{{Value: clusterBytes}}}\n// after: set TypeUrl on every Any so it matches the response TypeUrl\nresp := &discoverypb.DiscoveryResponse{TypeUrl: envoy.ClusterTypeURL, Resources: []*anypb.Any{{TypeUrl: envoy.ClusterTypeURL, Value: clusterBytes}}}","handlingStrategy":"try-catch","validationCode":"// Pre-validate each Any before handing the response to the client\nfor _, res := range resp.GetResources() {\n\tif res.GetTypeUrl() != resp.GetTypeUrl() {\n\t\treturn fmt.Errorf(\"skip response: resource typeUrl %s != %s\", res.GetTypeUrl(), resp.GetTypeUrl())\n\t}\n\tif _, err := res.UnmarshalNew(); err != nil {\n\t\treturn fmt.Errorf(\"skip response: unmarshal: %w\", err)\n\t}\n}","typeGuard":"func isSupportedResource(msg proto.Message) bool {\n\tswitch msg.(type) {\n\tcase *listenerpb.Listener, *clusterpb.Cluster, *endpointpb.ClusterLoadAssignment, *routepb.RouteConfiguration:\n\t\treturn true\n\t}\n\treturn false\n}","tryCatchPattern":"txs, err := sotw.tx(resp, get)\nif err != nil {\n\tvar perr *parseError\n\tif errors.As(err, &perr) {\n\t\tlog.Warnf(\"dropping malformed xDS response: %v\", err)\n\t\treturn nil, nil // skip batch, wait for server retry\n\t}\n\treturn nil, err\n}","preventionTips":["Always set TypeUrl on every Any to match the response's TypeUrl","Use anypb.New(msg) instead of hand-building Any values","Keep server and client envoy config API versions aligned (v3)","Log resource name/type on the server before pushing to catch malformed entries early"],"tags":["xds","grpc","parsing","istio"],"backgroundTag":"xds-resource-parse-failed","analyzedSha":"ac7b90affa4baf0642e6685319d56907b3a73a6d","analyzedAt":"2026-08-31T18:27:15.868Z","schemaVersion":2},"datasetVersion":"2026-08-31T19:17:28.585Z"}