grpc/grpc-go · critical
xds: `server_uri` field in server config cannot be empty: %s
Error message
xds: `server_uri` field in server config cannot be empty: %s
What it means
Returned by ServerConfig.UnmarshalJSON (internal/xds/bootstrap/bootstrap.go:399) when, after JSON parsing, the `server_uri` field is empty. The server URI is the address of the xDS management server and is mandatory; an empty value makes the server config unusable.
Source
Thrown at internal/xds/bootstrap/bootstrap.go:400
for _, cfg := range server.CallCredsConfigs {
c := bootstrap.GetCallCredentials(cfg.Type)
if c == nil {
// 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 RPCsView on GitHub (pinned to 03255a9237)
Solutions
- Add a non-empty `server_uri` to the offending server object (e.g. "trafficdirector.googleapis.com:443")
- Re-check the bootstrap template/secret injection that populates the URI
- Validate the bootstrap JSON for non-empty server_uri before use
Example fix
// before
{"channel_creds":[{"type":"insecure"}]}
// after
{"server_uri":"trafficdirector.googleapis.com:443","channel_creds":[{"type":"google_default"}]} Defensive patterns
Strategy: validation
Validate before calling
var probe struct {
XDSServers []struct{ ServerURI string `json:"server_uri"` } `json:"xds_servers"`
}
_ = json.Unmarshal(data, &probe)
for i, s := range probe.XDSServers {
if strings.TrimSpace(s.ServerURI) == "" {
return fmt.Errorf("xds_servers[%d] has empty server_uri", i)
}
} Try / catch
cfg, err := bootstrap.NewConfigFromContents(data)
if err != nil {
log.Fatalf("xDS bootstrap invalid (check server_uri): %v", err)
} Prevention
- Template-bootstrap checks should fail closed on empty server_uri
- Keep the URI in a single config variable to avoid drift
When it happens
Trigger: A server object in `xds_servers` omits `server_uri` (or sets it to ""), so after unmarshalling sc.serverURI is empty and the post-parse check fails.
Common situations: Hand-edited bootstrap file missing the field; templating that produced an empty URI; copy-paste that dropped server_uri when adapting an example.
Related errors
- 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
- failed to build credentials bundle from bootstrap for %q: %v
- failed to build call credentials from bootstrap for %q: %v
AI-assisted analysis of grpc/grpc-go@03255a9237 (2026-08-07).
Data as JSON: /api/errors/c5291cdad65e4fdf.
Report an issue: GitHub.