grpc/grpc-go · error
xds: json.Unmarshal( ) failed during bootstrap
Error message
xds: json.Unmarshal(%s) failed during bootstrap: %v
What it means
Returned by Config.UnmarshalJSON when the top-level json.Unmarshal of the bootstrap content into configJSON fails. The whole bootstrap document does not match the expected top-level schema (xds_servers, certificate_providers, authorities, node, etc.).
Solutions
- Run the bootstrap through jq to confirm it parses and inspect each top-level field type.
- Ensure authorities and certificate_providers are JSON objects (maps), xds_servers is an array, node is an object.
- Compare against a known-good bootstrap sample for your control plane.
- Regenerate the bootstrap from the control-plane tooling.
Example fix
// before (authorities wrong type)
"authorities": ["auth1"]
// after
"authorities": {"auth1":{"client_listener_resource_name_template":"xdstp://auth1/envoy.config.listener.v3.Listener/%s","xds_servers":[...]}} Defensive patterns
Strategy: validation
Validate before calling
// Lightweight structural check of top-level bootstrap types.
func validateBootstrapShape(data []byte) error {
var top map[string]json.RawMessage
if err := json.Unmarshal(data, &top); err != nil {
return err
}
if v, ok := top["authorities"]; ok {
var m map[string]json.RawMessage
if err := json.Unmarshal(v, &m); err != nil {
return fmt.Errorf("authorities must be an object: %w", err)
}
}
if v, ok := top["certificate_providers"]; ok {
var m map[string]json.RawMessage
if err := json.Unmarshal(v, &m); err != nil {
return fmt.Errorf("certificate_providers must be an object: %w", err)
}
}
return nil
} Try / catch
if _, err := bootstrap.NewConfigFromContents(data); err != nil {
log.Fatalf("bootstrap structural error: %v", err)
} Prevention
- Use a JSON schema validator in CI for bootstrap files.
- Keep authorities and certificate_providers as objects, never arrays.
- Start from a known-good sample when introducing a new field.
When it happens
Trigger: Triggered at bootstrap.go:598 when json.Unmarshal(data, &config) errors. Usually because a top-level field has the wrong JSON type, e.g. authorities is an array instead of an object, certificate_providers is a string, or node is not an object.
Common situations: Hand-edited bootstrap with structural type errors; mixing versions of the bootstrap format; pasting a YAML or a partial object into the bootstrap file.
Related errors
- xds: error normalizing JSON bootstrap configuration
- xds: failed to JSON unmarshal server configurations during…
- xds: failed to JSON unmarshal server configuration during…
- failed to build credentials bundle from bootstrap for
- failed to unmarshal config
AI-assisted analysis of grpc/grpc-go@0c51461d27 (2026-08-11).
Data as JSON: /api/errors/cbfbf1d0667fc52e.
Report an issue: GitHub.
Appendix: source
Thrown at internal/xds/bootstrap/bootstrap.go:598
XDSServers: c.xDSServers,
CertificateProviders: c.cpcs,
ServerListenerResourceNameTemplate: c.serverListenerResourceNameTemplate,
ClientDefaultListenerResourceNameTemplate: c.clientDefaultListenerResourceNameTemplate,
Authorities: c.authorities,
Node: c.node,
}
return json.MarshalIndent(config, " ", " ")
}
// UnmarshalJSON takes the json data (the complete bootstrap configuration) and
// unmarshals it to the struct.
func (c *Config) UnmarshalJSON(data []byte) error {
// Initialize the node field with client controlled values. This ensures
// even if the bootstrap configuration did not contain the node field, we
// will have a node field with client controlled fields alone.
config := configJSON{Node: newNode()}
if err := json.Unmarshal(data, &config); err != nil {
return fmt.Errorf("xds: json.Unmarshal(%s) failed during bootstrap: %v", string(data), err)
}
c.xDSServers = config.XDSServers
c.cpcs = config.CertificateProviders
c.serverListenerResourceNameTemplate = config.ServerListenerResourceNameTemplate
c.clientDefaultListenerResourceNameTemplate = config.ClientDefaultListenerResourceNameTemplate
c.authorities = config.Authorities
c.node = config.Node
// Build the certificate providers configuration to ensure that it is valid.
cpcCfgs := make(map[string]*certprovider.BuildableConfig)
getBuilder := internal.GetCertificateProviderBuilder.(func(string) certprovider.Builder)
for instance, nameAndConfig := range c.cpcs {
name := nameAndConfig.PluginName
parser := getBuilder(nameAndConfig.PluginName)
if parser == nil {
// We ignore plugins that we do not know about.
continueView on GitHub (pinned to 0c51461d27)