{"record":{"id":"6dc4f0e44e08d403","repo":"grpc/grpc-go","slug":"spiffe-bundlemapfrombytes-invalid-trust-domain","errorCode":null,"errorMessage":"spiffe: BundleMapFromBytes() invalid trust domain %q found when parsing SPIFFE Bundle Map: %v","messagePattern":"spiffe: BundleMapFromBytes\\(\\) invalid trust domain %q found when parsing SPIFFE Bundle Map: (.+?)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/credentials/spiffe/spiffe.go","lineNumber":55,"sourceCode":"// BundleMapFromBytes parses bytes into a SPIFFE Bundle Map. See the\n// SPIFFE Bundle Map spec for more detail -\n// https://github.com/spiffe/spiffe/blob/main/standards/SPIFFE_Trust_Domain_and_Bundle.md#4-spiffe-bundle-format\n// If duplicate keys are encountered in the JSON parsing, Go's default unmarshal\n// 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 {","sourceCodeStart":37,"sourceCodeEnd":73,"githubUrl":"https://github.com/grpc/grpc-go/blob/0c51461d27177d997e14c642fe18c11668fc09a3/internal/credentials/spiffe/spiffe.go#L37-L73","documentation":"Raised while iterating the parsed `trust_domains` map: a key could not be turned into a SPIFFE trust domain via spiffeid.TrustDomainFromString. Trust domain names must conform to the SPIFFE spec (lowercase RFC 1123 domain label: letters, digits, hyphens, dots per segment; no scheme, no path).","triggerScenarios":"A trust_domains key like `spiffe://example.org` (scheme not allowed in a trust domain name), `Example.Org` (uppercase), `my td` (space), `a_b` (underscore), or an empty string.","commonSituations":"Producer writes the full SPIFFE ID URI as the key instead of the bare trust domain; an upstream system normalizes inconsistently; hand-edited bundle map.","solutions":["Ensure each trust_domains key is the bare trust domain name (e.g. `example.org`), not a URI.","Restrict keys to lowercase letters, digits, hyphens, and dots; no underscores, spaces, or slashes.","Regenerate the bundle map from your SPIFFE federation endpoint so keys match the spec.","If you control the producer, write keys with spiffeid.TrustDomain.String() to guarantee validity."],"exampleFix":"// before\n{\"trust_domains\": {\"spiffe://example.org\": {...}}}\n// after\n{\"trust_domains\": {\"example.org\": {...}}}","handlingStrategy":"validation","validationCode":"var trustDomainRe = regexp.MustCompile(`^[a-z0-9]([a-z0-9\\-\\.]*[a-z0-9])?$`)\nfunc validTrustDomainKeys(b []byte) error {\n    var probe struct{ TD map[string]json.RawMessage `json:\"trust_domains\"` }\n    if err := json.Unmarshal(b, &probe); err != nil { return err }\n    for td := range probe.TD {\n        if !trustDomainRe.MatchString(td) { return fmt.Errorf(\"bad trust domain key: %q\", td) }\n    }\n    return nil\n}","typeGuard":null,"tryCatchPattern":"Pre-validate every trust_domains key with spiffeid.TrustDomainFromString before calling BundleMapFromBytes; collect all bad keys in one pass.","preventionTips":["Produce trust domain keys via spiffeid.TrustDomain.String() so they are always bare lowercase names.","Never write a full spiffe:// URI as the map key.","Review bundle maps produced by third parties for key format."],"tags":["grpc","spiffe","tls","security","config","parsing"],"backgroundTag":null,"analyzedSha":"0c51461d27177d997e14c642fe18c11668fc09a3","analyzedAt":"2026-08-11T14:49:15.055Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}