{"record":{"id":"20d1218eb3562d01","repo":"hyperledger/fabric","slug":"signature-policy-is-not-an-or-concatenation-nouto","errorCode":null,"errorMessage":"signature policy is not an OR concatenation, NOutOf %d","messagePattern":"signature policy is not an OR concatenation, NOutOf (.+?)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"core/chaincode/lifecycle/scc.go","lineNumber":908,"sourceCode":"\t\t\tif _, err := mspMgr.DeserializeIdentity(principal.Principal); err != nil {\n\t\t\t\treturn errors.Errorf(\"collection-name: %s -- contains an identity that is not part of the channel\", coll.GetName())\n\t\t\t}\n\n\t\tdefault:\n\t\t\treturn errors.Errorf(\"collection-name: %s -- principal type %v is not supported\", coll.GetName(), principal.PrincipalClassification)\n\t\t}\n\t}\n\treturn nil\n}\n\n// validateSpOrConcat checks if the supplied signature policy is just an OR-concatenation of identities\nfunc validateSpOrConcat(sp *common.SignaturePolicy) error {\n\tif sp.GetNOutOf() == nil {\n\t\treturn nil\n\t}\n\t// check if N == 1 (OR concatenation)\n\tif sp.GetNOutOf().N != 1 {\n\t\treturn errors.Errorf(\"signature policy is not an OR concatenation, NOutOf %d\", sp.GetNOutOf().N)\n\t}\n\t// recurse into all sub-rules\n\tfor _, rule := range sp.GetNOutOf().Rules {\n\t\terr := validateSpOrConcat(rule)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\treturn nil\n}\n\nfunc validateCollConfigsAgainstCommittedDef(\n\tproposedCollConfs []*pb.StaticCollectionConfig,\n\tcommittedCollConfPkg *pb.CollectionConfigPackage,\n) error {\n\tif committedCollConfPkg == nil || len(committedCollConfPkg.Config) == 0 {\n\t\treturn nil\n\t}","sourceCodeStart":890,"sourceCodeEnd":926,"githubUrl":"https://github.com/hyperledger/fabric/blob/2736b63f8fd5932511d56fe68b7039d15977f7f6/core/chaincode/lifecycle/scc.go#L890-L926","documentation":"Collection member orgs policies must be a flat OR concatenation of principals: every NOutOf rule must have N == 1 (an OR). This error is thrown when validateSpOrConcat encounters an NOutOf rule whose N is not 1, meaning the policy requires multiple principals jointly rather than any-one-of them.","triggerScenarios":"A collection config member_orgs_policy signature policy containing NOutOf with N >= 2 (e.g. AND of two orgs or a 2-of-3 rule), during collection config validation.","commonSituations":"Copying a chaincode endorsement policy (which allows M-of-N) into a collection member orgs policy; expressing 'both orgs must agree' requirements in private data distribution, which fabric does not support.","solutions":["Rewrite the policy so all branches are NOutOf with N=1 (pure OR of principals).","Express per-org requirements as separate principals in the OR list rather than AND-combining them.","If AND semantics are required, move that requirement into chaincode-level checks, not the collection policy.","Use a policy builder that produces OR-of-identities for collections."],"exampleFix":"// before: AND of two orgs (N=2)\nnOutOf := &common.SignaturePolicy_NOutOf{N: 2, Rules: rulesOfOrg1AndOrg2}\n// after: OR of both orgs (N=1)\nnOutOf := &common.SignaturePolicy_NOutOf{N: 1, Rules: []*common.SignaturePolicy{org1Member, org2Member}}","handlingStrategy":"validation","validationCode":"func assertORConcat(sp *common.SignaturePolicy) error {\n  if sp.GetNOutOf() == nil { return nil }\n  if sp.GetNOutOf().N != 1 { return fmt.Errorf(\"NOutOf %d not allowed in collection policy\", sp.GetNOutOf().N) }\n  for _, r := range sp.GetNOutOf().Rules {\n    if err := assertORConcat(r); err != nil { return err }\n  }\n  return nil\n}","typeGuard":"func isORConcat(sp *common.SignaturePolicy) bool {\n  if sp.GetNOutOf() == nil { return true }\n  if sp.GetNOutOf().N != 1 { return false }\n  for _, r := range sp.GetNOutOf().Rules {\n    if !isORConcat(r) { return false }\n  }\n  return true\n}","tryCatchPattern":"if err := approve(...); err != nil {\n  if strings.Contains(err.Error(), \"signature policy is not an OR concatenation\") {\n    // rewrite policy as OR of principals (N=1) and resubmit\n  }\n  return err\n}","preventionTips":["Never set N > 1 in NOutOf rules of a collection member orgs policy.","Do not copy endorsement policies into collection configs.","Add assertORConcat to pre-submission validation of collection configs."],"tags":["fabric","private-data","signature-policy","collection-config"],"backgroundTag":"unsupported-policy-structure","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"}