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
- Reduce t so that t <= n+1, e.g. OutOf(2, 'Org1.member', 'Org2.member').
- Dynamically clamp: if t > len(principals)+1, set t = len(principals) (or reject at config load).
- Validate the org/principal list wasn't truncated — adding the missing org may fix both t and n.
- 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
- Clamp or validate t <= len(principals)+1 at config load time.
- Compute 'majority' thresholds with t = n/2 + 1, not raw fractions.
- Re-derive t when the org/principal list changes (org removal breaks fixed t values).
- Prefer And ('all') / Or ('any') gates over raw OutOf where possible.
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
- unexpected type %s
- unrecognized type, expected a number, got %s
- error parsing principal %s
- '%s' not equal <newest|oldest|config|(number)>
- unmarshalling block: %s
AI-assisted analysis of hyperledger/fabric@2736b63f8f (2026-09-04).
Data as JSON: /api/errors/4fceb28b2c736134.
Report an issue: GitHub.