{"record":{"id":"8eb0c8bd6a479f06","repo":"hyperledger/fabric","slug":"no-principals-in-combinedprincipal","errorCode":null,"errorMessage":"No principals in CombinedPrincipal","messagePattern":"No principals in CombinedPrincipal","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"msp/mspimpl.go","lineNumber":464,"sourceCode":"}\n\n// collectPrincipals collects principals from combined principals into a single MSPPrincipal slice.\nfunc collectPrincipals(principal *m.MSPPrincipal, mspVersion MSPVersion) ([]*m.MSPPrincipal, error) {\n\tswitch principal.PrincipalClassification {\n\tcase m.MSPPrincipal_COMBINED:\n\t\t// Combined principals are not supported in MSP v1.0 or v1.1\n\t\tif mspVersion <= MSPv1_1 {\n\t\t\treturn nil, errors.Errorf(\"invalid principal type %d\", int32(principal.PrincipalClassification))\n\t\t}\n\t\t// Principal is a combination of multiple principals.\n\t\tprincipals := &m.CombinedPrincipal{}\n\t\terr := proto.Unmarshal(principal.Principal, principals)\n\t\tif err != nil {\n\t\t\treturn nil, errors.Wrap(err, \"could not unmarshal CombinedPrincipal from principal\")\n\t\t}\n\t\t// Return an error if there are no principals in the combined principal.\n\t\tif len(principals.Principals) == 0 {\n\t\t\treturn nil, errors.New(\"No principals in CombinedPrincipal\")\n\t\t}\n\t\t// Recursively call msp.collectPrincipals for all combined principals.\n\t\t// There is no limit for the levels of nesting for the combined principals.\n\t\tvar principalsSlice []*m.MSPPrincipal\n\t\tfor _, cp := range principals.Principals {\n\t\t\tinternalSlice, err := collectPrincipals(cp, mspVersion)\n\t\t\tif err != nil {\n\t\t\t\treturn nil, err\n\t\t\t}\n\t\t\tprincipalsSlice = append(principalsSlice, internalSlice...)\n\t\t}\n\t\t// All the combined principals have been collected into principalsSlice\n\t\treturn principalsSlice, nil\n\tdefault:\n\t\treturn []*m.MSPPrincipal{principal}, nil\n\t}\n}\n","sourceCodeStart":446,"sourceCodeEnd":482,"githubUrl":"https://github.com/hyperledger/fabric/blob/2736b63f8fd5932511d56fe68b7039d15977f7f6/msp/mspimpl.go#L446-L482","documentation":"A COMBINED MSPPrincipal successfully unmarshaled but contains zero nested principals, so collectPrincipals returns 'No principals in CombinedPrincipal'. An empty AND-group can never be satisfied meaningfully, so the library treats it as malformed policy input rather than 'always true' or 'always false'.","triggerScenarios":"Calling SatisfiesPrincipal/collectPrincipals with a COMBINED principal built from an empty principals list — e.g. an SDK policy builder given no sub-policies, a policy template never filled in, or a CombinedPrincipal constructed as &m.CombinedPrincipal{} and marshaled directly.","commonSituations":"Policy generation code paths where a list of organizations/roles was empty (missing config), default/template policies shipped unfilled, or tests intentionally constructing empty combined principals (TestCollectEmptyCombinedPrincipal) to assert this error.","solutions":["Ensure the CombinedPrincipal has at least one nested MSPPrincipal before marshaling and submitting the policy","Check upstream policy-building code/config for empty org/role lists that silently produce an empty CombinedPrincipal","If an empty group is semantically expected, restructure the policy (drop the combined wrapper or use an implicit meta policy)"],"exampleFix":"// before\nprincipal, _ := proto.Marshal(&m.CombinedPrincipal{}) // empty -> error\n// after\nif len(subPrincipals) == 0 {\n    return errors.New(\"cannot build CombinedPrincipal with no principals\")\n}\nprincipal, _ := proto.Marshal(&m.CombinedPrincipal{Principals: subPrincipals})","handlingStrategy":"validation","validationCode":"cp := &m.CombinedPrincipal{}\nif err := proto.Unmarshal(principal.Principal, cp); err != nil {\n    return err\n}\nif len(cp.Principals) == 0 {\n    return errors.New(\"CombinedPrincipal has no nested principals\")\n}\n// safe to call SatisfiesPrincipal","typeGuard":"func hasNestedPrincipals(b []byte) bool {\n    cp := &m.CombinedPrincipal{}\n    if proto.Unmarshal(b, cp) != nil {\n        return false\n    }\n    return len(cp.Principals) > 0\n}","tryCatchPattern":"ok, err := msp.SatisfiesPrincipal(id, principal)\nif err != nil {\n    if err.Error() == \"No principals in CombinedPrincipal\" {\n        // policy was built with an empty sub-principal list; rebuild the policy\n    }\n    return err\n}","preventionTips":["Reject empty org/role lists in policy-builder code before constructing CombinedPrincipal","Add unit tests asserting every COMBINED principal contains >= 1 nested MSPPrincipal","Never ship template policies unfilled; validate policy JSON/proto at generation time","When an empty group is intended, model it explicitly (implicit meta policy) rather than as an empty combined principal"],"tags":["policy","combined-principal","empty-policy","msp","hyperledger-fabric"],"backgroundTag":"empty-combined-principal","analyzedSha":"2736b63f8fd5932511d56fe68b7039d15977f7f6","analyzedAt":"2026-09-04T08:52:36.465Z","contentChangedAt":"2026-09-04T08:52:36.465Z","schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}