{"record":{"id":"7fb020fdb824e257","repo":"hyperledger/fabric","slug":"unrecognized-token-s-in-policy-string","errorCode":null,"errorMessage":"unrecognized token '%s' in policy string","messagePattern":"unrecognized token '(.+?)' in policy string","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"common/policydsl/policyparser.go","lineNumber":282,"sourceCode":"\t\tGateOr:                     or,\n\t\tstrings.ToLower(GateOr):    or,\n\t\tstrings.ToUpper(GateOr):    or,\n\t\tGateOutOf:                  outof,\n\t\tstrings.ToLower(GateOutOf): outof,\n\t\tstrings.ToUpper(GateOutOf): outof,\n\t}\n\tintermediate, err := expr.Compile(policy, expr.Env(env))\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tintermediateRes, err := expr.Run(intermediate, env)\n\tif err != nil {\n\t\t// attempt to produce a meaningful error\n\t\tif regexErr.MatchString(err.Error()) {\n\t\t\tsm := regexErr.FindStringSubmatch(err.Error())\n\t\t\tif len(sm) == 2 {\n\t\t\t\treturn nil, fmt.Errorf(\"unrecognized token '%s' in policy string\", sm[1])\n\t\t\t}\n\t\t}\n\n\t\treturn nil, err\n\t}\n\tresStr, ok := intermediateRes.(string)\n\tif !ok {\n\t\treturn nil, fmt.Errorf(\"invalid policy string '%s'\", policy)\n\t}\n\n\t// we still need two passes. The first pass just adds an extra\n\t// argument ID to each of the outof calls. This is\n\t// required because govaluate has no means of giving context\n\t// to user-implemented functions other than via arguments.\n\t// We need this argument because we need a global place where\n\t// we put the identities that the policy requires\n\tenv = map[string]interface{}{\n\t\t\"outof\": firstPass,","sourceCodeStart":264,"sourceCodeEnd":300,"githubUrl":"https://github.com/hyperledger/fabric/blob/2736b63f8fd5932511d56fe68b7039d15977f7f6/common/policydsl/policyparser.go#L264-L300","documentation":"FromString (common/policydsl/policyparser.go:282) evaluates the policy DSL with the expr library; when expr fails at runtime it matches the error against regexErr ('No parameter X found'). If it matches, FromString rewraps the failure as 'unrecognized token %s in policy string' to point at the exact offending token. This is the parser's way of flagging tokens that are not a recognized gate function (And/Or/OutOf in any case) or a defined principal.","triggerScenarios":"Calling policydsl.FromString with a policy containing an unknown identifier or misspelled gate, e.g. FromString(\"AND(Org1.member)\") is fine (case covered) but FromString(\"AND(Org1.member, BadGate(...))\") or any stray token like 'x' yields expr error 'No parameter x found' which is converted to this message.","commonSituations":"Typo'd gate names (e.g. 'outof' typo'd as 'outOf ' is fine since cases are covered, but things like 'AndOr', 'NOutOf', or an extra comma-produced empty operand); stray punctuation in policy strings placed in configtx.yaml or in Endorsement/Validation policy definitions; copying policy DSL from other systems that use different syntax.","solutions":["Check the token named in the error and correct its spelling; allowed gates are And/and/AND, Or/or/OR, OutOf/outof/OUTOF","Ensure every argument is a quoted principal 'MSP.role' with role in member|admin|client|peer|orderer, or a nested gate call","Validate the policy with policydsl.FromString in a test before putting it into channel or chaincode configuration","If the error is not token-related, look at the underlying expr error returned after this branch (the raw err is returned when the regex does not match)"],"exampleFix":"// before\nFromString(\"OutOf(1, 'Org1.member', Org2.peer)\") // Org2.peer unquoted -> token error\n// after\nFromString(\"OutOf(1, 'Org1.member', 'Org2.peer')\")","handlingStrategy":"validation","validationCode":"var policyTokenRe = regexp.MustCompile(`(?i)\\b(and|or|outof)\\s*\\(`)\nvar principalRe = regexp.MustCompile(`^[[:alnum:].-]+[.](member|admin|client|peer|orderer)$`)\n\nfunc validatePolicySyntax(policy string) error {\n\tif policy == \"\" || !policyTokenRe.MatchString(policy) {\n\t\treturn fmt.Errorf(\"policy %q must contain And/Or/OutOf gate calls\", policy)\n\t}\n\treturn nil\n}","typeGuard":null,"tryCatchPattern":"_, err := policydsl.FromString(policy)\nif err != nil {\n\tvar unrecognized string\n\tif m := regexp.MustCompile(`unrecognized token '([^']+)'`).FindStringSubmatch(err.Error()); m != nil {\n\t\tunrecognized = m[1]\n\t\treturn fmt.Errorf(\"policy %q: fix token %q (gate or quoted principal expected): %w\", policy, unrecognized, err)\n\t}\n\treturn err\n}","preventionTips":["Only use And/Or/OutOf gate names (any casing is accepted)","Quote every principal: 'Org1.member', never bare identifiers","Spell-check tokens named in the error before editing config files","Validate policies in CI by calling FromString on every configured policy string"],"tags":["hyperledger-fabric","policies","dsl-parsing","expr"],"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"}