cilium/cilium · error
parse resource: %w
Error message
parse resource: %w
What it means
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.
Source
Thrown at pkg/xds/experimental/client/client_sotw.go:56
for i := range curr.VersionedResources {
reqResourceNames.Insert(curr.VersionedResources[i].Name)
}
reqResourceNames.Insert(obsReq.resourceNames...)
return &discoverypb.DiscoveryRequest{
Node: node,
TypeUrl: obsReq.typeUrl,
ResourceNames: slices.Collect(maps.Keys(reqResourceNames)),
}
}
func (sotw *sotw) tx(resp *discoverypb.DiscoveryResponse, get getter) (txs, error) {
typeUrl := resp.GetTypeUrl()
upsertedResources := make(nameToResource)
for _, res := range resp.GetResources() {
msg, name, err := parseResource(typeUrl, res)
if err != nil {
return nil, fmt.Errorf("parse resource: %w", err)
}
upsertedResources[name] = msg
}
var deletedResources []string
if typeUrl == envoy.ListenerTypeURL || typeUrl == envoy.ClusterTypeURL {
deletedResources = findMissing(typeUrl, upsertedResources, get)
}
transactions := txs{{typeUrl: typeUrl, updated: upsertedResources, deleted: deletedResources}}
if typeUrl == envoy.ClusterTypeURL {
deletedResources := findMissing(envoy.EndpointTypeURL, upsertedResources, get)
transactions = append(transactions, tx{typeUrl: envoy.EndpointTypeURL, deleted: deletedResources})
}
return transactions, nil
}
func findMissing(typeUrl string, curr nameToResource, get getter) []string {View on GitHub (pinned to ac7b90affa)
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
Example fix
// before: server sends resources without setting type_url on each Any
resp := &discoverypb.DiscoveryResponse{TypeUrl: envoy.ClusterTypeURL, Resources: []*anypb.Any{{Value: clusterBytes}}}
// after: set TypeUrl on every Any so it matches the response TypeUrl
resp := &discoverypb.DiscoveryResponse{TypeUrl: envoy.ClusterTypeURL, Resources: []*anypb.Any{{TypeUrl: envoy.ClusterTypeURL, Value: clusterBytes}}} Defensive patterns
Strategy: try-catch
Validate before calling
// Pre-validate each Any before handing the response to the client
for _, res := range resp.GetResources() {
if res.GetTypeUrl() != resp.GetTypeUrl() {
return fmt.Errorf("skip response: resource typeUrl %s != %s", res.GetTypeUrl(), resp.GetTypeUrl())
}
if _, err := res.UnmarshalNew(); err != nil {
return fmt.Errorf("skip response: unmarshal: %w", err)
}
} Type guard
func isSupportedResource(msg proto.Message) bool {
switch msg.(type) {
case *listenerpb.Listener, *clusterpb.Cluster, *endpointpb.ClusterLoadAssignment, *routepb.RouteConfiguration:
return true
}
return false
} Try / catch
txs, err := sotw.tx(resp, get)
if err != nil {
var perr *parseError
if errors.As(err, &perr) {
log.Warnf("dropping malformed xDS response: %v", err)
return nil, nil // skip batch, wait for server retry
}
return nil, err
} Prevention
- 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
When it happens
Trigger: 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.
Common situations: 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).
Related errors
- missing name for typeUrl=%q
- nodeId is empty
- type URL is required for ADS
- mismatching type URL
- unknown type URL
AI-assisted analysis of cilium/cilium@ac7b90affa (2026-08-31).
Data as JSON: /api/errors/640cf38e2334bac7.
Report an issue: GitHub.