grpc/grpc-go · error
failed to unmarshal config: %v
Error message
failed to unmarshal config: %v
What it means
tlscreds.NewBundle (bundle.go:62-64) unmarshals the provided json.RawMessage into a struct expecting certificate_file, ca_certificate_file, private_key_file, and spiffe_trust_bundle_map_file string fields. If the JSON is invalid or a field has the wrong value type, encoding/json fails and the error is wrapped here.
Source
Thrown at internal/xds/bootstrap/tlscreds/bundle.go:64
}
// NewBundle returns a credentials.Bundle which implements mTLS Credentials in xDS
// Bootstrap File. It delegates certificate loading to a file_watcher provider
// if either client certificates or server root CA is specified. The second
// return value is a close func that should be called when the caller no longer
// needs this bundle.
// See gRFC A65: github.com/grpc/proposal/blob/master/A65-xds-mtls-creds-in-bootstrap.md
func NewBundle(jd json.RawMessage) (credentials.Bundle, func(), error) {
cfg := &struct {
CertificateFile string `json:"certificate_file"`
CACertificateFile string `json:"ca_certificate_file"`
PrivateKeyFile string `json:"private_key_file"`
SPIFFETrustBundleMapFile string `json:"spiffe_trust_bundle_map_file"`
}{}
if jd != nil {
if err := json.Unmarshal(jd, cfg); err != nil {
return nil, nil, fmt.Errorf("failed to unmarshal config: %v", err)
}
} // Else the config field is absent. Treat it as an empty config.
if !envconfig.XDSSPIFFEEnabled {
cfg.SPIFFETrustBundleMapFile = ""
}
if cfg.CACertificateFile == "" && cfg.CertificateFile == "" && cfg.PrivateKeyFile == "" && cfg.SPIFFETrustBundleMapFile == "" {
// We cannot use (and do not need) a file_watcher provider in this case,
// and can simply directly use the TLS transport credentials.
// Quoting A65:
//
// > The only difference between the file-watcher certificate provider
// > config and this one is that in the file-watcher certificate
// > provider, at least one of the "certificate_file" or
// > "ca_certificate_file" fields must be specified, whereas in this
// > configuration, it is acceptable to specify neither one.
// Further, with the introduction of SPIFFE Trust Map support, we also
// check for this value.View on GitHub (pinned to 03255a9237)
Solutions
- Validate that the credentials config is a JSON object with only string-valued fields (certificate_file, ca_certificate_file, private_key_file, spiffe_trust_bundle_map_file).
- Run the config sub-document through a JSON validator.
- Ensure all file-path values are quoted strings.
Example fix
// before:
// { "certificate_file": /etc/certs/client.pem }
// after:
// { "certificate_file": "/etc/certs/client.pem",
// "private_key_file": "/etc/certs/client.key",
// "ca_certificate_file": "/etc/certs/ca.pem" } Defensive patterns
Strategy: validation
Validate before calling
// Validate the TLS creds config JSON structure.
func validateTLSCredsConfig(jd json.RawMessage) error {
if jd == nil { return nil }
var cfg struct {
CertificateFile *string `json:"certificate_file"`
CACertificateFile *string `json:"ca_certificate_file"`
PrivateKeyFile *string `json:"private_key_file"`
SPIFFETrustBundleMapFile *string `json:"spiffe_trust_bundle_map_file"`
}
return json.Unmarshal(jd, &cfg)
} Prevention
- Quote all file-path values in the credentials config.
- Validate the mTLS sub-document with a JSON parser before deploy.
When it happens
Trigger: The xDS TLS credentials config block (mTLS in bootstrap, gRFC A65) is malformed JSON, or one of its fields is a number/object instead of a string. Note: a nil config is allowed and treated as empty, so this only fires when jd is non-nil but invalid.
Common situations: The mTLS config was hand-edited and a path was left unquoted; a templating system injected a structured value where a string was expected; the config was copied from a YAML source without conversion.
Related errors
- failed to build credentials bundle from bootstrap for %q: %v
- failed to unmarshal JWT call credentials config: %v
- xDS TLS credentials only support one mode
- failed to build call credentials from bootstrap for %q: %v
- xds: `channel_creds` field in server config cannot be empty:
AI-assisted analysis of grpc/grpc-go@03255a9237 (2026-08-07).
Data as JSON: /api/errors/10c210b21d48c364.
Report an issue: GitHub.