{"record":{"id":"c3a60e55c3aa5db8","repo":"grpc/grpc-go","slug":"spiffe-bundlemapfrombytes-no-bundles-parsed-fro","errorCode":null,"errorMessage":"spiffe: BundleMapFromBytes() no bundles parsed from spiffe bundle map bytes","messagePattern":"spiffe: BundleMapFromBytes\\(\\) no bundles parsed from spiffe bundle map bytes","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/credentials/spiffe/spiffe.go","lineNumber":49,"sourceCode":")\n\ntype partialParsedSPIFFEBundleMap struct {\n\tBundles map[string]json.RawMessage `json:\"trust_domains\"`\n}\n\n// 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.","sourceCodeStart":31,"sourceCodeEnd":67,"githubUrl":"https://github.com/grpc/grpc-go/blob/0c51461d27177d997e14c642fe18c11668fc09a3/internal/credentials/spiffe/spiffe.go#L31-L67","documentation":"Raised by spiffe.BundleMapFromBytes after JSON unmarshalling succeeded but the `trust_domains` field was absent or null, so result.Bundles is nil. The input bytes are valid JSON but not a SPIFFE Bundle Map per the spec.","triggerScenarios":"Calling spiffe.BundleMapFromBytes on bytes that are a single SPIFFE Bundle (not a Bundle Map), an empty JSON object `{}`, a JSON with a typo'd key like `\"bundles\"` instead of `\"trust_domains\"`, or the JSON value `null`.","commonSituations":"Loading a bundle file when the bundle-map file was expected; key name mismatch between producer and consumer; feeding an empty/malformed config from a secret mount.","solutions":["Confirm the input is a SPIFFE Bundle Map: a JSON object whose top-level key is `trust_domains` mapping trust-domain names to bundle objects.","If you actually have a single bundle, parse it with spiffebundle.Parse / spiffebundle.Load instead of BundleMapFromBytes.","Check the file was mounted/served completely and not truncated to `{}`.","Validate the JSON has a non-null `trust_domains` key before calling."],"exampleFix":"// before\nm, err := spiffe.BundleMapFromBytes(singleBundleBytes) // wrong: this is one bundle, not a map\n// after\nb, err := spiffebundle.Parse(trustDomain, singleBundleBytes)","handlingStrategy":"validation","validationCode":"func isBundleMap(b []byte) bool {\n    var probe struct{ TrustDomains map[string]json.RawMessage `json:\"trust_domains\"` }\n    if err := json.Unmarshal(b, &probe); err != nil { return false }\n    return probe.TrustDomains != nil\n}\n// call before spiffe.BundleMapFromBytes","typeGuard":null,"tryCatchPattern":"If you must call BundleMapFromBytes on untrusted bytes, wrap it: on error fall back to spiffebundle.Parse if the input is actually a single bundle, else propagate the error.","preventionTips":["Distinguish single SPIFFE Bundles from SPIFFE Bundle Maps at the file level (different extensions/sources).","Source bundle maps only from a trusted SPIFFE Bundle Endpoint.","Reject empty or `{}` inputs before parsing."],"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"}