hyperledger/fabric · error

invalid t-out-of-n predicate, t %d, n %d

Error message

invalid t-out-of-n predicate, t %d, n %d

What it means

After parsing the threshold t and counting the n subjects, secondPass validates 0 <= t <= n+1. A negative t or a t larger than n+1 can never be satisfied (or is nonsensical), so it returns 'invalid t-out-of-n predicate, t <t>, n <n>'. t == n+1 is deliberately allowed as a special 'never satisfiable by all' case used by the DSL.

Source

Thrown at common/policydsl/policyparser.go:159

	/* get the second argument, we expect an integer telling us
	   how many of the remaining we expect to have*/
	var t int
	switch arg := args[1].(type) {
	case float64:
		t = int(arg)
	case int:
		t = arg
	default:
		return nil, fmt.Errorf("unrecognized type, expected a number, got %s", reflect.TypeOf(args[1]))
	}

	/* get the n in the t out of n */
	n := len(args) - 2

	/* sanity check - t should be positive, permit equal to n+1, but disallow over n+1 */
	if t < 0 || t > n+1 {
		return nil, fmt.Errorf("invalid t-out-of-n predicate, t %d, n %d", t, n)
	}

	policies := make([]*cb.SignaturePolicy, 0)

	/* handle the rest of the arguments */
	for _, principal := range args[2:] {
		switch t := principal.(type) {
		/* if it's a string, we expect it to be formed as
		   <MSP_ID> . <ROLE>, where MSP_ID is the MSP identifier
		   and ROLE is either a member, an admin, a client, a peer or an orderer*/
		case string:
			/* split the string */
			subm := regex.FindAllStringSubmatch(t, -1)
			if subm == nil || len(subm) != 1 || len(subm[0]) != 4 {
				return nil, fmt.Errorf("error parsing principal %s", t)
			}

			/* get the right role */

View on GitHub (pinned to 2736b63f8f)

Solutions

  1. Reduce t so that t <= n+1, e.g. OutOf(2, 'Org1.member', 'Org2.member').
  2. Dynamically clamp: if t > len(principals)+1, set t = len(principals) (or reject at config load).
  3. Validate the org/principal list wasn't truncated — adding the missing org may fix both t and n.
  4. Use And/Or gates instead of raw OutOf when you mean 'all' or 'any'.

Example fix

// before
t := 3
if t > len(orgs)+1 { /* still passed through */ }
policydsl.FromString("OutOf(3, 'Org1.member', 'Org2.member')") // t=3, n=2, ok; but OutOf(4,...) fails
// after
t := len(orgs) // or clamp: if t > len(orgs)+1 { t = len(orgs) }
policydsl.FromString("OutOf(2, 'Org1.member', 'Org2.member')")
Defensive patterns

Strategy: validation

Validate before calling

func validThreshold(t, n int) bool {
	return t >= 0 && t <= n+1
}
// before building the policy string:
if !validThreshold(cfg.T, len(cfg.Principals)) {
	return fmt.Errorf("t=%d invalid for n=%d principals", cfg.T, len(cfg.Principals))
}

Try / catch

policy, err := policydsl.FromString(spec)
if err != nil && strings.Contains(err.Error(), "invalid t-out-of-n predicate") {
	return nil, fmt.Errorf("endorsement threshold exceeds principal count: %w", err)
}

Prevention

When it happens

Trigger: Policies like OutOf(3, 'Org1.member', 'Org2.member') (t=3, n=2 exceeds n+1=3? no — this fires at t>n+1, e.g. t=4, n=2), OutOf(0,...) is fine but OutOf(-1,...) fails, or programmatic gates computing t from config with an off-by-one.

Common situations: Channel/mod policy config where the endorsement requirement exceeds the number of listed orgs; template-generated policies with hardcoded t values after orgs were removed; arithmetic mistakes computing 'majority' thresholds (e.g. t = 2*n/3 + 2 overshooting n+1 for tiny n).

Related errors


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