hyperledger/fabric · error
No principals in CombinedPrincipal
Error message
No principals in CombinedPrincipal
What it means
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'.
Source
Thrown at msp/mspimpl.go:464
}
// collectPrincipals collects principals from combined principals into a single MSPPrincipal slice.
func collectPrincipals(principal *m.MSPPrincipal, mspVersion MSPVersion) ([]*m.MSPPrincipal, error) {
switch principal.PrincipalClassification {
case m.MSPPrincipal_COMBINED:
// Combined principals are not supported in MSP v1.0 or v1.1
if mspVersion <= MSPv1_1 {
return nil, errors.Errorf("invalid principal type %d", int32(principal.PrincipalClassification))
}
// Principal is a combination of multiple principals.
principals := &m.CombinedPrincipal{}
err := proto.Unmarshal(principal.Principal, principals)
if err != nil {
return nil, errors.Wrap(err, "could not unmarshal CombinedPrincipal from principal")
}
// Return an error if there are no principals in the combined principal.
if len(principals.Principals) == 0 {
return nil, errors.New("No principals in CombinedPrincipal")
}
// Recursively call msp.collectPrincipals for all combined principals.
// There is no limit for the levels of nesting for the combined principals.
var principalsSlice []*m.MSPPrincipal
for _, cp := range principals.Principals {
internalSlice, err := collectPrincipals(cp, mspVersion)
if err != nil {
return nil, err
}
principalsSlice = append(principalsSlice, internalSlice...)
}
// All the combined principals have been collected into principalsSlice
return principalsSlice, nil
default:
return []*m.MSPPrincipal{principal}, nil
}
}
View on GitHub (pinned to 2736b63f8f)
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)
Example fix
// before
principal, _ := proto.Marshal(&m.CombinedPrincipal{}) // empty -> error
// after
if len(subPrincipals) == 0 {
return errors.New("cannot build CombinedPrincipal with no principals")
}
principal, _ := proto.Marshal(&m.CombinedPrincipal{Principals: subPrincipals}) Defensive patterns
Strategy: validation
Validate before calling
cp := &m.CombinedPrincipal{}
if err := proto.Unmarshal(principal.Principal, cp); err != nil {
return err
}
if len(cp.Principals) == 0 {
return errors.New("CombinedPrincipal has no nested principals")
}
// safe to call SatisfiesPrincipal Type guard
func hasNestedPrincipals(b []byte) bool {
cp := &m.CombinedPrincipal{}
if proto.Unmarshal(b, cp) != nil {
return false
}
return len(cp.Principals) > 0
} Try / catch
ok, err := msp.SatisfiesPrincipal(id, principal)
if err != nil {
if err.Error() == "No principals in CombinedPrincipal" {
// policy was built with an empty sub-principal list; rebuild the policy
}
return err
} Prevention
- 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
When it happens
Trigger: 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.
Common situations: 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.
Related errors
- Failed getting local MSP principal during channelless check
- failed verifying that the signed data identity satisfies loc
- MSP Principal role [%s] not recognized
- could not unmarshal CombinedPrincipal from principal
- could not unmarshal MSPRole from principal
AI-assisted analysis of hyperledger/fabric@2736b63f8f (2026-09-04).
Data as JSON: /api/errors/8eb0c8bd6a479f06.
Report an issue: GitHub.