grpc/grpc-go · error
recovered from panic during resource parsing, resource: %v,
Error message
recovered from panic during resource parsing, resource: %v, panic: %v
What it means
Emitted (as a returned error, leading to a NACK) when a ResourceType.Decoder.Decode call panics and envconfig.XDSRecoverPanicInResourceParsing is enabled. The panic is recovered into this error message so one malformed resource does not crash the process; the resource is treated as a per-resource/top-level decode error and NACKed to the server.
Source
Thrown at internal/xds/clients/xdsclient/channel.go:260
timestamp := time.Now()
md := xdsresource.UpdateMetadata{
Version: resp.version,
Timestamp: timestamp,
}
opts := &DecodeOptions{
Config: xc.clientConfig,
ServerConfig: xc.serverConfig,
}
topLevelErrors := make([]error, 0) // Tracks deserialization errors, where we don't have a resource name.
perResourceErrors := make(map[string]error) // Tracks resource validation errors, where we have a resource name.
ret := make(map[string]dataAndErrTuple) // Return result, a map from resource name to either resource data or error.
for _, r := range resp.resources {
result, err := func() (res *DecodeResult, err error) {
defer func() {
if envconfig.XDSRecoverPanicInResourceParsing {
if p := recover(); p != nil {
err = fmt.Errorf("recovered from panic during resource parsing, resource: %v, panic: %v", r, p)
}
}
}()
return rType.Decoder.Decode(NewAnyProto(r), *opts)
}()
// Name field of the result is left unpopulated only when resource
// deserialization fails.
name := ""
if result == nil && err == nil {
xc.logger.Errorf("Decode() returned nil result and nil error for resource: %v", r)
continue
}
if result != nil {
name = xdsresource.ParseName(result.Name).String()
}
if err == nil {
ret[name] = dataAndErrTuple{Resource: result.Resource}View on GitHub (pinned to 03255a9237)
Solutions
- Read the panic stack in the log (the %v includes the recovered value) and identify which decoder/resource type faulted.
- Report or fix the decoder bug; for custom ResourceType implementations, add nil/type checks before assertions.
- If the resource itself is bad, correct the server-side configuration so the client stops receiving it.
- Disable the env override only if you need the process to crash for debugging; leaving it on is recommended in production.
Defensive patterns
Strategy: fallback
Try / catch
// The client converts the panic into a NACK; surface NACK errors via the
// ResourceError watcher callback and log the resource for follow-up.
func (w *myWatcher) ResourceError(err error, done func()) {
defer done()
logger.Errorf("xDS resource NACK: %v", err)
} Prevention
- Keep GRPC_XDS_RECOVER_PANIC_IN_RESOURCE_PARSING enabled in production to avoid process crashes.
- For custom ResourceType decoders, add nil/type checks and unit tests with malformed inputs.
- Track which resource triggered the panic from the log and disable/fix it server-side.
When it happens
Trigger: A specific resource in an ADS response triggers a panic inside a registered ResourceType decoder (nil dereference, index out of range, assertion failure). Only seen when GRPC_XDS_RECOVER_PANIC_IN_RESOURCE_PARSING-style env override is on; otherwise the panic propagates.
Common situations: A malformed or unexpected resource shape from the server exposing a decoder bug, a custom ResourceType implementation with a nil pointer path, or a proto version mismatch causing a type assertion to fail inside the decoder.
Related errors
- unexpected message type %T
- xds: failed to create transport for server config %v: %v
- missing fallback credentials
- ClientHandshake() is not supported for server credentials
- ServerHandshake is not supported for client credentials
AI-assisted analysis of grpc/grpc-go@03255a9237 (2026-08-07).
Data as JSON: /api/errors/c6e9bc0caaea7b05.
Report an issue: GitHub.