hyperledger/fabric · error
signature policy is not an OR concatenation, NOutOf %d
Error message
signature policy is not an OR concatenation, NOutOf %d
What it means
validateSpOrConcat enforces that a collection's MemberOrgsPolicy signature policy is only a concatenation of OR rules (any-of semantics, NOutOf with N==1, possibly nested). If any NOutOf node in the policy tree has N != 1 (e.g. a 2-of-3 rule), the policy is rejected because collection membership policies must express 'any of these organizations'.
Source
Thrown at core/handlers/validation/builtin/v13/lscc_validation_logic.go:110
}
// make sure that the signature policy is meaningful (only consists of ORs)
err := validateSpOrConcat(newCollection.MemberOrgsPolicy.GetSignaturePolicy().Rule)
if err != nil {
return errors.WithMessagef(err, "collection-name: %s -- error in member org policy", collectionName)
}
}
return nil
}
// validateSpOrConcat checks if the supplied signature policy is just an OR-concatenation of identities
func validateSpOrConcat(sp *common.SignaturePolicy) error {
if sp.GetNOutOf() == nil {
return nil
}
// check if N == 1 (OR concatenation)
if sp.GetNOutOf().N != 1 {
return errors.New(fmt.Sprintf("signature policy is not an OR concatenation, NOutOf %d", sp.GetNOutOf().N))
}
// recurse into all sub-rules
for _, rule := range sp.GetNOutOf().Rules {
err := validateSpOrConcat(rule)
if err != nil {
return err
}
}
return nil
}
func checkForMissingCollections(newCollectionsMap map[string]*pb.StaticCollectionConfig, oldCollectionConfigs []*pb.CollectionConfig,
) error {
var missingCollections []string
// In the new collection config package, ensure that there is one entry per old collection. Any
// number of new collections are allowed.
for _, oldCollectionConfig := range oldCollectionConfigs {View on GitHub (pinned to 2736b63f8f)
Solutions
- Rewrite the member orgs policy so every NOutOf node has N==1, listing organizations as OR-ed principals
- Use the collections config helpers so the policy is built as an OR concatenation of the desired org MSP principals
- Do not reuse chaincode endorsement policies verbatim as collection member policies; only the 'any org' subset is allowed
Example fix
// before
policy := &common.SignaturePolicy{Type: &common.SignaturePolicy_NOutOf{NOutOf: &common.SignaturePolicy_NOutOf{N: 2, Rules: rules}}}
// after
policy := &common.SignaturePolicy{Type: &common.SignaturePolicy_NOutOf{NOutOf: &common.SignaturePolicy_NOutOf{N: 1, Rules: rules}}} Defensive patterns
Strategy: validation
Validate before calling
function validateMemberOrgsPolicy(policy) {
const walk = (sp) => {
if (sp.nOutOf) {
if (sp.nOutOf.n !== 1) throw new Error('member orgs policy must be an OR concatenation (nOutOf n=1)');
sp.nOutOf.rules.forEach(walk);
}
};
walk(policy);
} Type guard
function isOrConcatPolicy(sp) {
if (!sp || !sp.nOutOf) return true;
return sp.nOutOf.n === 1 && sp.nOutOf.rules.every(isOrConcatPolicy);
} Try / catch
try {
await contract.submitTransaction('DeployChaincode', ...args);
} catch (err) {
if (String(err).includes('not an OR concatenation')) {
// rebuild memberOrgsPolicy with n=1 rules
}
throw err;
} Prevention
- Never reuse endorsement policies (which use N-of semantics) as collection member policies
- Build member policies only from OR-ed principal lists
- Add a unit test that walks any policy tree asserting n==1 at each NOutOf node
When it happens
Trigger: Defining a collection whose memberOrgsPolicy signaturePolicy contains an NOutOf rule with N > 1 (or effectively 0) anywhere in the tree, submitted as part of a collection config during chaincode definition.
Common situations: Building the SignaturePolicyEnvelope programmatically with common.SignaturePolicy_NOutOf{N: 2, ...}; converting an endorsement policy (which often uses N-of semantics) and reusing it as a collection member policy; policy YAML/JSON with 'signedBy' counts.
Related errors
- collection-name: %s -- maximum peer count (%d) cannot be les
- collection-name: %s -- requiredPeerCount (%d) cannot be less
- the following existing collections are missing in the new co
- empty collection-name is not allowed
- collection-name: %s not allowed. A valid collection name fol
AI-assisted analysis of hyperledger/fabric@2736b63f8f (2026-09-04).
Data as JSON: /api/errors/308717c3bef79548.
Report an issue: GitHub.