grpc/grpc-go · critical

failed to build credentials bundle from bootstrap for %q: %v

Error message

failed to build credentials bundle from bootstrap for %q: %v

What it means

Returned by ServerConfig.UnmarshalJSON (internal/xds/bootstrap/bootstrap.go:367) when the first supported channel-credentials type's Build() returns an error. Bootstrap iterates `channel_creds`, looks up each type via bootstrap.GetChannelCredentials, and tries to build a bundle; the first Build error is fatal.

Source

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

	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
		sc.credsDialOption = grpc.WithCredentialsBundle(bundle)
		if d, ok := bundle.(extraDialOptions); ok {
			sc.extraDialOptions = d.DialOptions()
		}
		sc.cleanups = append(sc.cleanups, cancel)
		break
	}

	if envconfig.XDSBootstrapCallCredsEnabled {
		// Process call credentials - unlike channel creds, we use ALL supported
		// types. Also, call credentials are optional as per gRFC A97.
		for _, cfg := range server.CallCredsConfigs {
			c := bootstrap.GetCallCredentials(cfg.Type)
			if c == nil {
				// Skip unsupported call credential types (don't fail bootstrap).
				continue

View on GitHub (pinned to 03255a9237)

Solutions

  1. Read the wrapped error (%v) — it states why Build failed (missing file, no ADC, etc.)
  2. Fix the credentials config (correct paths, install ADC, register the cert provider)
  3. Fall back to a creds type that builds, e.g. "insecure" for testing

Example fix

// before: TLS config points at non-existent files
{"type":"tls","config":{"ca_data":"...","cert_path":"/missing/cert","key_path":"/missing/key"}}
// after: use a creds type that builds in this environment
{"type":"insecure"}
Defensive patterns

Strategy: validation

Validate before calling

// Pre-flight: ensure the creds material the bootstrap references exists.
for _, cc := range serverChannelCreds {
    switch cc.Type {
    case "tls":
        var cfg struct {
            CertPath string `json:"cert_path"`
            KeyPath  string `json:"key_path"`
        }
        _ = json.Unmarshal(cc.Config, &cfg)
        if cfg.CertPath != "" {
            if _, err := os.Stat(cfg.CertPath); err != nil { return err }
        }
    case "google_default":
        if os.Getenv("GOOGLE_APPLICATION_CREDENTIALS") == "" {
            log.Printf("warning: GOOGLE_APPLICATION_CREDENTIALS unset; ADC may be unavailable")
        }
    }
}

Try / catch

cfg, err := bootstrap.NewConfigFromContents(data)
if err != nil {
    if strings.Contains(err.Error(), "credentials bundle") {
        log.Fatalf("bootstrap channel creds failed to build: %v", err)
    }
}

Prevention

When it happens

Trigger: A `channel_creds` entry names a known type (e.g. a TLS/cert-provider type or google_default) but its Build() fails — e.g. invalid TLS config, a cert provider plugin that cannot load its material, or google_default with no application-default credentials available.

Common situations: TLS creds config referencing a missing cert/key path; google_default in an environment without ADC; a cert-provider plugin misconfigured; credentials plugin not registered but type name recognized.

Related errors


AI-assisted analysis of grpc/grpc-go@03255a9237 (2026-08-07). Data as JSON: /api/errors/faa843dd9d8c82c5. Report an issue: GitHub.