{"record":{"id":"f88eb5b6ce618131","repo":"hyperledger/fabric","slug":"unrecognized-type-expected-a-principal-or-a-polic","errorCode":null,"errorMessage":"unrecognized type, expected a principal or a policy, got %s","messagePattern":"unrecognized type, expected a principal or a policy, got (.+?)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"common/policydsl/policyparser.go","lineNumber":224,"sourceCode":"\n\t\t\t/* create a SignaturePolicy that requires a signature from\n\t\t\t   the principal we've just built*/\n\t\t\tdapolicy := SignedBy(int32(ctx.IDNum))\n\t\t\tpolicies = append(policies, dapolicy)\n\n\t\t\t/* increment the identity counter. Note that this is\n\t\t\t   suboptimal as we are not reusing identities. We\n\t\t\t   can deduplicate them easily and make this puppy\n\t\t\t   smaller. For now it's fine though */\n\t\t\t// TODO: deduplicate principals\n\t\t\tctx.IDNum++\n\n\t\t/* if we've already got a policy we're good, just append it */\n\t\tcase *cb.SignaturePolicy:\n\t\t\tpolicies = append(policies, t)\n\n\t\tdefault:\n\t\t\treturn nil, fmt.Errorf(\"unrecognized type, expected a principal or a policy, got %s\", reflect.TypeOf(principal))\n\t\t}\n\t}\n\n\treturn NOutOf(int32(t), policies), nil\n}\n\ntype context struct {\n\tIDNum      int\n\tprincipals []*mb.MSPPrincipal\n}\n\nfunc newContext() *context {\n\treturn &context{IDNum: 0, principals: make([]*mb.MSPPrincipal, 0)}\n}\n\n// FromString takes a string representation of the policy,\n// parses it and returns a SignaturePolicyEnvelope that\n// implements that policy. The supported language is as follows:","sourceCodeStart":206,"sourceCodeEnd":242,"githubUrl":"https://github.com/hyperledger/fabric/blob/2736b63f8fd5932511d56fe68b7039d15977f7f6/common/policydsl/policyparser.go#L206-L242","documentation":"secondPass in common/policydsl/policyparser.go:224 rejects an argument to an OutOf/And/Or gate that is neither a principal string nor a nested *cb.SignaturePolicy. The internal expression pipeline should only ever produce strings (principals like 'Org1.member') or previously built SignaturePolicy values; any other type reaching this switch means the generated expression was malformed or a function returned an unexpected type.","triggerScenarios":"Calling policydsl.FromString with an expression argument inside a gate that is not a quoted principal and not a gate call, e.g. FromString(\"OutOf(1, Org1.member, 42)\") or a bare identifier - expr passes it through and the switch's default branch fires.","commonSituations":"Typos in policy strings in channel configtx.yaml or policy definitions in chaincode (e.g. missing quotes around an MSP identifier, unbalanced parentheses causing arguments to shift, or passing numeric/naked tokens where 'OrgMSP.peer' style principals are expected).","solutions":["Quote the argument so it parses as a principal string of the form '<MSP_ID>.<role>' where role is one of member|admin|client|peer|orderer, e.g. OutOf(1, 'Org1.member')","Check for unbalanced or misplaced parentheses that shift arguments between nested gates","Ensure every argument to And/Or/OutOf is either a quoted principal or a nested gate call, never a number or bare identifier","Test the policy string through policydsl.FromString in a unit test before deploying it in channel or chaincode policy config"],"exampleFix":"// before\nFromString(\"OutOf(1, Org1.member, 2)\")\n// after\nFromString(\"OutOf(1, 'Org1.member', 'Org1.peer')\")","handlingStrategy":"validation","validationCode":"var principalRe = regexp.MustCompile(`^[[:alnum:].-]+[.](member|admin|client|peer|orderer)$`)\n\nfunc validatePolicyArgs(policy string) error {\n\tif !strings.Contains(policy, \"And(\") && !strings.Contains(policy, \"Or(\") && !strings.Contains(policy, \"OutOf(\") &&\n\t\t!strings.Contains(policy, \"and(\") && !strings.Contains(policy, \"or(\") && !strings.Contains(policy, \"outof(\") {\n\t\treturn fmt.Errorf(\"policy %q must be rooted in And/Or/OutOf\", policy)\n\t}\n\treturn nil\n}\n// plus: every non-gate argument must match principalRe","typeGuard":null,"tryCatchPattern":"_, err := policydsl.FromString(policy)\nif err != nil && strings.Contains(err.Error(), \"unrecognized type, expected a principal or a policy\") {\n\treturn fmt.Errorf(\"policy %q has a non-principal argument in a gate: %w\", policy, err)\n}","preventionTips":["Quote every principal argument ('Org1.member') so it is passed as a string","Only use member|admin|client|peer|orderer as the role suffix","Keep every argument to And/Or/OutOf either a quoted principal or a nested gate call","Unit-test all policy strings with FromString before committing them to config"],"tags":["hyperledger-fabric","policies","dsl-parsing","signature-policy"],"backgroundTag":"policy-parse-error","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"}