grpc/grpc-go · critical
xds: failed to JSON unmarshal server configuration during bo
Error message
xds: failed to JSON unmarshal server configuration during bootstrap: %v, config: %s
What it means
Returned by ServerConfig.UnmarshalJSON (internal/xds/bootstrap/bootstrap.go:351) when a single server object inside `xds_servers` fails to unmarshal into serverConfigJSON. This is the per-entry variant of the bootstrap unmarshal failure and is fatal to bootstrap.
Source
Thrown at internal/xds/bootstrap/bootstrap.go:352
ServerURI: sc.serverURI,
ChannelCreds: sc.channelCreds,
CallCredsConfigs: sc.callCredsConfigs,
ServerFeatures: sc.serverFeatures,
}
return json.Marshal(server)
}
// extraDialOptions captures custom dial options specified via
// credentials.Bundle.
type extraDialOptions interface {
DialOptions() []grpc.DialOption
}
// UnmarshalJSON takes the json data (a server) and unmarshals it to the struct.
func (sc *ServerConfig) UnmarshalJSON(data []byte) error {
server := serverConfigJSON{}
if err := json.Unmarshal(data, &server); err != nil {
return fmt.Errorf("xds: failed to JSON unmarshal server configuration during bootstrap: %v, config:\n%s", err, string(data))
}
sc.serverURI = server.ServerURI
sc.channelCreds = server.ChannelCreds
sc.callCredsConfigs = server.CallCredsConfigs
sc.serverFeatures = server.ServerFeatures
for _, cc := range server.ChannelCreds {
// We stop at the first credential type that we support.
c := bootstrap.GetChannelCredentials(cc.Type)
if c == nil {
continue
}
bundle, cancel, err := c.Build(cc.Config)
if err != nil {
return fmt.Errorf("failed to build credentials bundle from bootstrap for %q: %v", cc.Type, err)
}
sc.selectedChannelCreds = ccView on GitHub (pinned to 03255a9237)
Solutions
- Inspect the offending server object printed in the error and fix its JSON
- Ensure each server has `server_uri` and an array `channel_creds` of {type,config}
- Re-validate the whole bootstrap file against the schema
Example fix
// before
{"server_uri":"xds.example.com","channel_creds":"insecure"}
// after
{"server_uri":"xds.example.com","channel_creds":[{"type":"insecure"}]} Defensive patterns
Strategy: validation
Validate before calling
var probe struct {
XDSServers []struct {
ServerURI string `json:"server_uri"`
ChannelCreds []json.RawMessage `json:"channel_creds"`
} `json:"xds_servers"`
}
_ = json.Unmarshal(data, &probe)
for i, s := range probe.XDSServers {
if s.ServerURI == "" || len(s.ChannelCreds) == 0 {
return fmt.Errorf("xds_servers[%d] invalid: missing server_uri or channel_creds", i)
}
} Try / catch
cfg, err := bootstrap.NewConfigFromContents(data)
if err != nil {
log.Fatalf("xDS bootstrap server entry invalid: %v", err)
} Prevention
- Validate each server entry has server_uri and an array channel_creds
- Use the same schema check in config templating
When it happens
Trigger: One element of the `xds_servers` array is not a valid server object — e.g. a JSON syntax error within that entry, an unexpected field type, or a malformed `channel_creds`/`call_creds` sub-object.
Common situations: A specific server entry has a typo (e.g. `channel_creds` set to a string instead of an array); partial/corrupt bootstrap file; mismatched schema version for one server.
Related errors
- missing server_listener_resource_name_template in the bootst
- xds: failed to JSON unmarshal server configurations during b
- failed to build credentials bundle from bootstrap for %q: %v
- failed to build call credentials from bootstrap for %q: %v
- xds: `server_uri` field in server config cannot be empty: %s
AI-assisted analysis of grpc/grpc-go@03255a9237 (2026-08-07).
Data as JSON: /api/errors/58a44bc70195a43e.
Report an issue: GitHub.