grpc/grpc-go · error

xds: failed to JSON unmarshal server configurations during…

Error message

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

What it means

Returned by ServerConfigs.UnmarshalJSON when the 'xds_servers' array of the bootstrap file cannot be unmarshalled into []*ServerConfig. The offending JSON payload is included so you can see the exact malformed input.

Solutions

  1. Open the bootstrap file and confirm xds_servers is a JSON array of server objects.
  2. Run the file through a JSON validator (e.g. jq . bootstrap.json) to surface syntax errors.
  3. Ensure each element has the expected fields (server_uri, channel_creds).
  4. Regenerate the bootstrap from your control-plane tooling (e.g. gke xds bootstrap generator) if hand-editing introduced errors.

Example fix

// before (xds_servers not an array)
"xds_servers": {"server_uri":"trafficdirector.googleapis.com:443"}

// after
"xds_servers": [{"server_uri":"trafficdirector.googleapis.com:443","channel_creds":[{"type":"google_default"}]}]
Defensive patterns

Strategy: validation

Validate before calling

// Validate that xds_servers is a JSON array of objects before bootstrap.
func validateBootstrapServers(raw json.RawMessage) error {
    var arr []json.RawMessage
    if err := json.Unmarshal(raw, &arr); err != nil {
        return fmt.Errorf("xds_servers must be a JSON array: %w", err)
    }
    if len(arr) == 0 {
        return fmt.Errorf("xds_servers must not be empty")
    }
    return nil
}

Try / catch

// GetConfiguration returns the error; fail fast at startup.
if _, err := bootstrap.GetConfiguration(); err != nil {
    log.Fatalf("bootstrap invalid: %v", err)
}

Prevention

When it happens

Trigger: Triggered at bootstrap.go:144 when json.Unmarshal(data, &servers) fails for the xds_servers field. Typically the value is not a JSON array, or contains elements that are not objects convertible to ServerConfig.

Common situations: xds_servers set to a single object instead of an array; array elements are strings or numbers instead of objects; stray trailing comma producing invalid JSON; copy-paste error merging two bootstrap files.

Related errors


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

Appendix: source

Thrown at internal/xds/bootstrap/bootstrap.go:144

// Equal returns true if scs equals other.
func (scs *ServerConfigs) Equal(other *ServerConfigs) bool {
	if len(*scs) != len(*other) {
		return false
	}
	for i := range *scs {
		if !(*scs)[i].Equal((*other)[i]) {
			return false
		}
	}
	return true
}

// UnmarshalJSON takes the json data (a list of server configurations) and
// unmarshals it to the struct.
func (scs *ServerConfigs) UnmarshalJSON(data []byte) error {
	servers := []*ServerConfig{}
	if err := json.Unmarshal(data, &servers); err != nil {
		return fmt.Errorf("xds: failed to JSON unmarshal server configurations during bootstrap: %v, config:\n%s", err, string(data))
	}
	*scs = servers
	return nil
}

// String returns a string representation of the ServerConfigs, by concatenating
// the string representations of the underlying server configs.
func (scs *ServerConfigs) String() string {
	ret := ""
	for i, sc := range *scs {
		if i > 0 {
			ret += ", "
		}
		ret += sc.String()
	}
	return ret
}

View on GitHub (pinned to 0c51461d27)