{"record":{"id":"4fceb28b2c736134","repo":"hyperledger/fabric","slug":"invalid-t-out-of-n-predicate-t-d-n-d","errorCode":null,"errorMessage":"invalid t-out-of-n predicate, t %d, n %d","messagePattern":"invalid t-out-of-n predicate, t (.+?), n (.+?)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"common/policydsl/policyparser.go","lineNumber":159,"sourceCode":"\n\t/* get the second argument, we expect an integer telling us\n\t   how many of the remaining we expect to have*/\n\tvar t int\n\tswitch arg := args[1].(type) {\n\tcase float64:\n\t\tt = int(arg)\n\tcase int:\n\t\tt = arg\n\tdefault:\n\t\treturn nil, fmt.Errorf(\"unrecognized type, expected a number, got %s\", reflect.TypeOf(args[1]))\n\t}\n\n\t/* get the n in the t out of n */\n\tn := len(args) - 2\n\n\t/* sanity check - t should be positive, permit equal to n+1, but disallow over n+1 */\n\tif t < 0 || t > n+1 {\n\t\treturn nil, fmt.Errorf(\"invalid t-out-of-n predicate, t %d, n %d\", t, n)\n\t}\n\n\tpolicies := make([]*cb.SignaturePolicy, 0)\n\n\t/* handle the rest of the arguments */\n\tfor _, principal := range args[2:] {\n\t\tswitch t := principal.(type) {\n\t\t/* if it's a string, we expect it to be formed as\n\t\t   <MSP_ID> . <ROLE>, where MSP_ID is the MSP identifier\n\t\t   and ROLE is either a member, an admin, a client, a peer or an orderer*/\n\t\tcase string:\n\t\t\t/* split the string */\n\t\t\tsubm := regex.FindAllStringSubmatch(t, -1)\n\t\t\tif subm == nil || len(subm) != 1 || len(subm[0]) != 4 {\n\t\t\t\treturn nil, fmt.Errorf(\"error parsing principal %s\", t)\n\t\t\t}\n\n\t\t\t/* get the right role */","sourceCodeStart":141,"sourceCodeEnd":177,"githubUrl":"https://github.com/hyperledger/fabric/blob/2736b63f8fd5932511d56fe68b7039d15977f7f6/common/policydsl/policyparser.go#L141-L177","documentation":"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.","triggerScenarios":"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.","commonSituations":"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).","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'."],"exampleFix":"// before\nt := 3\nif t > len(orgs)+1 { /* still passed through */ }\npolicydsl.FromString(\"OutOf(3, 'Org1.member', 'Org2.member')\") // t=3, n=2, ok; but OutOf(4,...) fails\n// after\nt := len(orgs) // or clamp: if t > len(orgs)+1 { t = len(orgs) }\npolicydsl.FromString(\"OutOf(2, 'Org1.member', 'Org2.member')\")","handlingStrategy":"validation","validationCode":"func validThreshold(t, n int) bool {\n\treturn t >= 0 && t <= n+1\n}\n// before building the policy string:\nif !validThreshold(cfg.T, len(cfg.Principals)) {\n\treturn fmt.Errorf(\"t=%d invalid for n=%d principals\", cfg.T, len(cfg.Principals))\n}","typeGuard":null,"tryCatchPattern":"policy, err := policydsl.FromString(spec)\nif err != nil && strings.Contains(err.Error(), \"invalid t-out-of-n predicate\") {\n\treturn nil, fmt.Errorf(\"endorsement threshold exceeds principal count: %w\", err)\n}","preventionTips":["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."],"tags":["policydsl","hyperledger-fabric","validation","threshold","t-out-of-n"],"backgroundTag":"invalid-policy-threshold","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"}