{"record":{"id":"a5c3046ee2f0159a","repo":"grpc/grpc-go","slug":"spiffe-bundlemapfrombytes-failed-to-parse-bundl","errorCode":null,"errorMessage":"spiffe: BundleMapFromBytes() failed to parse bundle for trust domain %q: %v","messagePattern":"spiffe: BundleMapFromBytes\\(\\) failed to parse bundle for trust domain %q: (.+?)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/credentials/spiffe/spiffe.go","lineNumber":59,"sourceCode":"// behavior occurs which causes the last processed entry to be the entry in the\n// parsed map.\nfunc BundleMapFromBytes(bundleMapBytes []byte) (map[string]*spiffebundle.Bundle, error) {\n\tvar result partialParsedSPIFFEBundleMap\n\tif err := json.Unmarshal(bundleMapBytes, &result); err != nil {\n\t\treturn nil, err\n\t}\n\tif result.Bundles == nil {\n\t\treturn nil, fmt.Errorf(\"spiffe: BundleMapFromBytes() no bundles parsed from spiffe bundle map bytes\")\n\t}\n\tbundleMap := map[string]*spiffebundle.Bundle{}\n\tfor td, jsonBundle := range result.Bundles {\n\t\ttrustDomain, err := spiffeid.TrustDomainFromString(td)\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"spiffe: BundleMapFromBytes() invalid trust domain %q found when parsing SPIFFE Bundle Map: %v\", td, err)\n\t\t}\n\t\tbundle, err := spiffebundle.Parse(trustDomain, jsonBundle)\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"spiffe: BundleMapFromBytes() failed to parse bundle for trust domain %q: %v\", td, err)\n\t\t}\n\t\tbundleMap[td] = bundle\n\t}\n\treturn bundleMap, nil\n}\n\n// GetRootsFromSPIFFEBundleMap returns the root trust certificates from the\n// SPIFFE bundle map for the given trust domain from the leaf certificate.\nfunc GetRootsFromSPIFFEBundleMap(bundleMap map[string]*spiffebundle.Bundle, leafCert *x509.Certificate) (*x509.CertPool, error) {\n\t// 1. Upon receiving a peer certificate, verify that it is a well-formed SPIFFE\n\t//    leaf certificate.  In particular, it must have a single URI SAN containing\n\t//    a well-formed SPIFFE ID ([SPIFFE ID format]).\n\tspiffeID, err := idFromCert(leafCert)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"spiffe: could not get spiffe ID from peer leaf cert but verification with spiffe trust map was configured: %v\", err)\n\t}\n\n\t// 2. Use the trust domain in the peer certificate's SPIFFE ID to lookup","sourceCodeStart":41,"sourceCodeEnd":77,"githubUrl":"https://github.com/grpc/grpc-go/blob/03255a9237b6eb32710f6bc4f2de9a675b99fe36/internal/credentials/spiffe/spiffe.go#L41-L77","documentation":"Returned when spiffebundle.Parse fails for an individual trust domain entry inside the Bundle Map. After the key validates, the value is handed to the go-spiffe bundle parser which expects X.509 authorities (as DER or PEM cert array) and optional JWT keys; malformed certs, missing required fields, or wrong JSON shapes trigger this error wrapping the underlying parse failure.","triggerScenarios":"A trust_domains entry whose value is not a valid SPIFFE bundle object: e.g. x509_authorities not present or containing non-PEM/non-base64 data, a JSON array where an object is expected, expired/revoked cert bytes that x509.ParseCertificate rejects.","commonSituations":"Truncated bundle file; copy/paste of a PEM block that lost its BEGIN/END markers; mismatch between the bundle version produced by an old SPIRE and the parser's expectations; encoding issues (raw bytes instead of base64 DER).","solutions":["Re-fetch the bundle for that trust domain from its authoritative source (SPIRE bundle endpoint).","Verify the x509_authorities entries parse with crypto/x509 before packaging them.","Ensure DER certs are base64-encoded as the SPIFFE bundle JSON spec requires.","Diff the offending bundle against a known-good one to spot truncation or encoding regressions."],"exampleFix":"// before\n{\"trust_domains\": {\"prod\": {\"x509_authorities\": \"not-a-cert\"}}}\n\n// after\n{\"trust_domains\": {\"prod\": {\"x509_authorities\": [{\"x509_asn\": \"<base64-DER>\"}]}}}","handlingStrategy":"try-catch","validationCode":"func bundlesParse(b map[string]*spiffebundle.Bundle, raw []byte) error {\n    var pm struct{ TrustDomains map[string]json.RawMessage `json:\"trust_domains\"` }\n    if err := json.Unmarshal(raw, &pm); err != nil { return err }\n    for td, jb := range pm.TrustDomains {\n        if _, err := spiffebundle.Parse(spiffeid.RequireTrustDomainFromString(td), jb); err != nil {\n            return fmt.Errorf(\"trust domain %s: %w\", td, err)\n        }\n    }\n    return nil\n}","typeGuard":null,"tryCatchPattern":"bm, err := spiffe.BundleMapFromBytes(raw)\nif err != nil {\n    if strings.Contains(err.Error(), \"failed to parse bundle\") {\n        // identify the offending trust domain from the error, re-fetch just that bundle\n    }\n    return err\n}","preventionTips":["Re-fetch bundles from authoritative SPIRE endpoints on parse failure.","Pre-validate x509_authorities entries with crypto/x509 before packaging.","Version your bundle format and reject incompatible producers at load time."],"tags":["grpc","spiffe","certificate","trust-bundle","json-parsing"],"analyzedSha":"03255a9237b6eb32710f6bc4f2de9a675b99fe36","analyzedAt":"2026-08-07T00:29:34.215Z","schemaVersion":2},"datasetVersion":"2026-08-07T03:17:09.362Z"}