hyperledger/fabric · error

unrecognized token '%s' in policy string

Error message

unrecognized token '%s' in policy string

What it means

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.

Source

Thrown at common/policydsl/policyparser.go:282

		GateOr:                     or,
		strings.ToLower(GateOr):    or,
		strings.ToUpper(GateOr):    or,
		GateOutOf:                  outof,
		strings.ToLower(GateOutOf): outof,
		strings.ToUpper(GateOutOf): outof,
	}
	intermediate, err := expr.Compile(policy, expr.Env(env))
	if err != nil {
		return nil, err
	}

	intermediateRes, err := expr.Run(intermediate, env)
	if err != nil {
		// attempt to produce a meaningful error
		if regexErr.MatchString(err.Error()) {
			sm := regexErr.FindStringSubmatch(err.Error())
			if len(sm) == 2 {
				return nil, fmt.Errorf("unrecognized token '%s' in policy string", sm[1])
			}
		}

		return nil, err
	}
	resStr, ok := intermediateRes.(string)
	if !ok {
		return nil, fmt.Errorf("invalid policy string '%s'", policy)
	}

	// we still need two passes. The first pass just adds an extra
	// argument ID to each of the outof calls. This is
	// required because govaluate has no means of giving context
	// to user-implemented functions other than via arguments.
	// We need this argument because we need a global place where
	// we put the identities that the policy requires
	env = map[string]interface{}{
		"outof": firstPass,

View on GitHub (pinned to 2736b63f8f)

Solutions

  1. Check the token named in the error and correct its spelling; allowed gates are And/and/AND, Or/or/OR, OutOf/outof/OUTOF
  2. Ensure every argument is a quoted principal 'MSP.role' with role in member|admin|client|peer|orderer, or a nested gate call
  3. Validate the policy with policydsl.FromString in a test before putting it into channel or chaincode configuration
  4. 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)

Example fix

// before
FromString("OutOf(1, 'Org1.member', Org2.peer)") // Org2.peer unquoted -> token error
// after
FromString("OutOf(1, 'Org1.member', 'Org2.peer')")
Defensive patterns

Strategy: validation

Validate before calling

var policyTokenRe = regexp.MustCompile(`(?i)\b(and|or|outof)\s*\(`)
var principalRe = regexp.MustCompile(`^[[:alnum:].-]+[.](member|admin|client|peer|orderer)$`)

func validatePolicySyntax(policy string) error {
	if policy == "" || !policyTokenRe.MatchString(policy) {
		return fmt.Errorf("policy %q must contain And/Or/OutOf gate calls", policy)
	}
	return nil
}

Try / catch

_, err := policydsl.FromString(policy)
if err != nil {
	var unrecognized string
	if m := regexp.MustCompile(`unrecognized token '([^']+)'`).FindStringSubmatch(err.Error()); m != nil {
		unrecognized = m[1]
		return fmt.Errorf("policy %q: fix token %q (gate or quoted principal expected): %w", policy, unrecognized, err)
	}
	return err
}

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Related errors


AI-assisted analysis of hyperledger/fabric@2736b63f8f (2026-09-04). Data as JSON: /api/errors/7fb020fdb824e257. Report an issue: GitHub.