grpc/grpc-go · critical
xds: `channel_creds` field in server config cannot be empty:
Error message
xds: `channel_creds` field in server config cannot be empty: %s
What it means
Returned by ServerConfig.UnmarshalJSON (internal/xds/bootstrap/bootstrap.go:402) when no supported channel credentials could be built — i.e. credsDialOption stayed nil after iterating `channel_creds`. This means either `channel_creds` was empty, or every entry named a type not registered via bootstrap.GetChannelCredentials, or none of the registered types built successfully before the loop completed without selecting one.
Source
Thrown at internal/xds/bootstrap/bootstrap.go:403
// Skip unsupported call credential types (don't fail bootstrap).
continue
}
callCreds, cancel, err := c.Build(cfg.Config)
if err != nil {
// Call credential validation failed - this should fail bootstrap.
return fmt.Errorf("failed to build call credentials from bootstrap for %q: %v", cfg.Type, err)
}
sc.selectedCallCreds = append(sc.selectedCallCreds, callCreds)
sc.extraDialOptions = append(sc.extraDialOptions, grpc.WithPerRPCCredentials(callCreds))
sc.cleanups = append(sc.cleanups, cancel)
}
}
if sc.serverURI == "" {
return fmt.Errorf("xds: `server_uri` field in server config cannot be empty: %s", string(data))
}
if sc.credsDialOption == nil {
return fmt.Errorf("xds: `channel_creds` field in server config cannot be empty: %s", string(data))
}
return nil
}
// ServerConfigTestingOptions specifies options for creating a new ServerConfig
// for testing purposes.
//
// # Testing-Only
type ServerConfigTestingOptions struct {
// URI is the name of the server corresponding to this server config.
URI string
// ChannelCreds contains a list of channel credentials to use when talking
// to this server. If unspecified, `insecure` credentials will be used.
ChannelCreds []ChannelCreds
// CallCredsConfigs contains a list of call credentials to use for individual RPCs
// to this server. Optional.
CallCredsConfigs []CallCredsConfig
// ServerFeatures represents the list of features supported by this server.View on GitHub (pinned to 03255a9237)
Solutions
- Add at least one supported channel creds type, e.g. "insecure" or "google_default"
- Import the package that registers any custom channel credentials so GetChannelCredentials finds it
- Ensure the `channel_creds` array is non-empty in every server object
Example fix
// before
{"server_uri":"xds.example.com:443"}
// after
{"server_uri":"xds.example.com:443","channel_creds":[{"type":"insecure"}]} Defensive patterns
Strategy: validation
Validate before calling
var probe struct {
XDSServers []struct{ ChannelCreds []json.RawMessage `json:"channel_creds"` } `json:"xds_servers"`
}
_ = json.Unmarshal(data, &probe)
for i, s := range probe.XDSServers {
if len(s.ChannelCreds) == 0 {
return fmt.Errorf("xds_servers[%d] has empty channel_creds", i)
}
} Try / catch
cfg, err := bootstrap.NewConfigFromContents(data)
if err != nil {
if strings.Contains(err.Error(), "channel_creds") {
log.Fatalf("bootstrap has no supported channel creds: %v", err)
}
} Prevention
- Always include at least one supported channel creds type per server
- Import packages that register custom channel creds
- Default to "insecure" in local dev, "google_default"/TLS in prod
When it happens
Trigger: A server object has an empty `channel_creds` array, or lists only credential types the binary does not support (e.g. a custom creds type never registered), so no bundle is selected and credsDialOption remains nil.
Common situations: Bootstrap file with `channel_creds` omitted entirely; only unsupported types listed; a credentials plugin whose init/registration was not imported; testing without at least an "insecure" entry.
Related errors
- failed to build credentials bundle from bootstrap for %q: %v
- failed to build call credentials from bootstrap for %q: %v
- missing server_listener_resource_name_template in the bootst
- xds: failed to JSON unmarshal server configurations during b
- xds: failed to JSON unmarshal server configuration during bo
AI-assisted analysis of grpc/grpc-go@03255a9237 (2026-08-07).
Data as JSON: /api/errors/f3b6a16987c45aaf.
Report an issue: GitHub.