grpc/grpc-go · error

xds: failed to JSON unmarshal server configuration during…

Error message

xds: failed to JSON unmarshal server configuration during bootstrap: %v, config:
%s

What it means

Returned by ServerConfig.UnmarshalJSON when an individual server entry inside xds_servers fails to unmarshal into the serverConfigJSON struct (server_uri, channel_creds, call_creds, server_features). The raw server JSON is printed.

Solutions

  1. Locate the failing server block using the printed JSON.
  2. Confirm each field type matches the schema: server_uri string, channel_creds array of {type,config?}, call_creds array, server_features array of strings.
  3. Validate with a JSON schema for the bootstrap (gRFC xDS bootstrap format).
  4. Remove optional fields rather than leaving them as wrong-typed placeholders.

Example fix

// before (channel_creds wrong type)
{"server_uri":"td:443","channel_creds":"google_default"}

// after
{"server_uri":"td:443","channel_creds":[{"type":"google_default"}]}
Defensive patterns

Strategy: validation

Validate before calling

// Validate a single server config object shape.
func validateServerObject(raw json.RawMessage) error {
    var s struct {
        ServerURI    string            `json:"server_uri"`
        ChannelCreds []json.RawMessage `json:"channel_creds"`
    }
    if err := json.Unmarshal(raw, &s); err != nil {
        return fmt.Errorf("server object invalid: %w", err)
    }
    return nil
}

Try / catch

if _, err := bootstrap.NewConfigFromContents(data); err != nil {
    return fmt.Errorf("bootstrap parse failed (check server blocks): %w", err)
}

Prevention

When it happens

Trigger: Triggered at bootstrap.go:352 when json.Unmarshal(data, &server) fails for one element of the xds_servers array. Typically one field has an unexpected type, e.g. channel_creds is a string instead of an array of objects.

Common situations: channel_creds spelled wrong or set to a bare string; server_uri is a number; call_creds/server_features not arrays; whitespace or unicode issues inside one server block.

Related errors


AI-assisted analysis of grpc/grpc-go@0c51461d27 (2026-08-11). Data as JSON: /api/errors/58a44bc70195a43e. Report an issue: GitHub.

Appendix: 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 = cc

View on GitHub (pinned to 0c51461d27)