{"record":{"id":"10c210b21d48c364","repo":"grpc/grpc-go","slug":"failed-to-unmarshal-config-v","errorCode":null,"errorMessage":"failed to unmarshal config: %v","messagePattern":"failed to unmarshal config: (.+?)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/xds/bootstrap/tlscreds/bundle.go","lineNumber":64,"sourceCode":"}\n\n// NewBundle returns a credentials.Bundle which implements mTLS Credentials in xDS\n// Bootstrap File. It delegates certificate loading to a file_watcher provider\n// if either client certificates or server root CA is specified. The second\n// return value is a close func that should be called when the caller no longer\n// needs this bundle.\n// See gRFC A65: github.com/grpc/proposal/blob/master/A65-xds-mtls-creds-in-bootstrap.md\nfunc NewBundle(jd json.RawMessage) (credentials.Bundle, func(), error) {\n\tcfg := &struct {\n\t\tCertificateFile          string `json:\"certificate_file\"`\n\t\tCACertificateFile        string `json:\"ca_certificate_file\"`\n\t\tPrivateKeyFile           string `json:\"private_key_file\"`\n\t\tSPIFFETrustBundleMapFile string `json:\"spiffe_trust_bundle_map_file\"`\n\t}{}\n\n\tif jd != nil {\n\t\tif err := json.Unmarshal(jd, cfg); err != nil {\n\t\t\treturn nil, nil, fmt.Errorf(\"failed to unmarshal config: %v\", err)\n\t\t}\n\t} // Else the config field is absent. Treat it as an empty config.\n\n\tif !envconfig.XDSSPIFFEEnabled {\n\t\tcfg.SPIFFETrustBundleMapFile = \"\"\n\t}\n\tif cfg.CACertificateFile == \"\" && cfg.CertificateFile == \"\" && cfg.PrivateKeyFile == \"\" && cfg.SPIFFETrustBundleMapFile == \"\" {\n\t\t// We cannot use (and do not need) a file_watcher provider in this case,\n\t\t// and can simply directly use the TLS transport credentials.\n\t\t// Quoting A65:\n\t\t//\n\t\t// > The only difference between the file-watcher certificate provider\n\t\t// > config and this one is that in the file-watcher certificate\n\t\t// > provider, at least one of the \"certificate_file\" or\n\t\t// > \"ca_certificate_file\" fields must be specified, whereas in this\n\t\t// > configuration, it is acceptable to specify neither one.\n\t\t// Further, with the introduction of SPIFFE Trust Map support, we also\n\t\t// check for this value.","sourceCodeStart":46,"sourceCodeEnd":82,"githubUrl":"https://github.com/grpc/grpc-go/blob/03255a9237b6eb32710f6bc4f2de9a675b99fe36/internal/xds/bootstrap/tlscreds/bundle.go#L46-L82","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before:\n//   { \"certificate_file\": /etc/certs/client.pem }\n// after:\n//   { \"certificate_file\": \"/etc/certs/client.pem\",\n//     \"private_key_file\": \"/etc/certs/client.key\",\n//     \"ca_certificate_file\": \"/etc/certs/ca.pem\" }","handlingStrategy":"validation","validationCode":"// Validate the TLS creds config JSON structure.\nfunc validateTLSCredsConfig(jd json.RawMessage) error {\n    if jd == nil { return nil }\n    var cfg struct {\n        CertificateFile          *string `json:\"certificate_file\"`\n        CACertificateFile        *string `json:\"ca_certificate_file\"`\n        PrivateKeyFile           *string `json:\"private_key_file\"`\n        SPIFFETrustBundleMapFile *string `json:\"spiffe_trust_bundle_map_file\"`\n    }\n    return json.Unmarshal(jd, &cfg)\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Quote all file-path values in the credentials config.","Validate the mTLS sub-document with a JSON parser before deploy."],"tags":["xds","bootstrap","tls","mtls","credentials","json","grpc"],"analyzedSha":"03255a9237b6eb32710f6bc4f2de9a675b99fe36","analyzedAt":"2026-08-07T00:29:34.215Z","schemaVersion":2},"datasetVersion":"2026-08-07T03:17:09.362Z"}