hyperledger/fabric · error
unrecognized type, expected a number, got %s
Error message
unrecognized type, expected a number, got %s
What it means
secondPass expects its second argument to be the threshold t, and only accepts float64 or int (float64 because the expression evaluator treats numbers as float64). Any other type in the threshold slot fails with 'unrecognized type, expected a number, got <T>'.
Source
Thrown at common/policydsl/policyparser.go:151
/* get the first argument, we expect it to be the context */
var ctx *context
switch v := args[0].(type) {
case *context:
ctx = v
default:
return nil, fmt.Errorf("unrecognized type, expected the context, got %s", reflect.TypeOf(args[0]))
}
/* 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*/View on GitHub (pinned to 2736b63f8f)
Solutions
- Write the threshold unquoted and numeric in the policy: OutOf(2, ...) not OutOf('2', ...).
- Convert the threshold to int (or float64) before any direct secondPass call: secondPass(ctx, int(t), ...).
- Reject/normalize non-numeric thresholds in code that assembles policies from user config.
- Check upstream gate functions (and/or) — they inject len(args) or 1, so a custom wrapper must do the same.
Example fix
// before
policydsl.FromString("OutOf('2', 'Org1.member', 'Org2.member')")
// after
policydsl.FromString("OutOf(2, 'Org1.member', 'Org2.member')") Defensive patterns
Strategy: type-guard
Validate before calling
switch args[1].(type) {
case int, float64:
// ok
default:
return fmt.Errorf("threshold must be numeric, got %T", args[1])
} Type guard
func isNumericThreshold(v any) bool {
switch v.(type) {
case int, float64:
return true
}
return false
} Try / catch
if err != nil && strings.Contains(err.Error(), "expected a number") {
return nil, fmt.Errorf("policy threshold must be unquoted and numeric: %w", err)
} Prevention
- Write thresholds unquoted: OutOf(2, ...), never OutOf('2', ...).
- Convert int64/uint64/float32 thresholds to int before gate construction.
- Validate user-supplied threshold config parses as an integer at load time.
When it happens
Trigger: An intermediate string where the second outof argument is not numeric — e.g. 'outof(ID, "2", ...)' produced by a gate whose threshold was a quoted string, or calling secondPass directly with a string/int64 threshold.
Common situations: User policies like "OutOf('2', 'Org1.member')" where the threshold was quoted and survives as a string into secondPass; programmatic gate construction passing int64/uint64 thresholds; locale/templating code turning numbers into strings.
Related errors
- unexpected type %s
- unrecognized type, expected the context, got %s
- invalid t-out-of-n predicate, t %d, n %d
- expected at least two arguments to NOutOf. Given %d
- at least 3 arguments expected, got %d
AI-assisted analysis of hyperledger/fabric@2736b63f8f (2026-09-04).
Data as JSON: /api/errors/5fa23aec60fbac27.
Report an issue: GitHub.