hyperledger/fabric · error

unexpected type %s

Error message

unexpected type %s

What it means

In outof(), the first argument is the threshold t of a t-out-of-n policy and must be a float64, int, or string. Any other type (bool, struct, nil, etc.) cannot be rendered into the intermediate policy string, so the library fails with 'unexpected type <T>'.

Source

Thrown at common/policydsl/policyparser.go:65

// This will be evaluated by second/third passes to convert to a proto policy
func outof(args ...any) (any, error) {
	var toret strings.Builder
	toret.WriteString("outof(")

	if len(args) < 2 {
		return nil, fmt.Errorf("expected at least two arguments to NOutOf. Given %d", len(args))
	}

	arg0 := args[0]
	// govaluate treats all numbers as float64 only. But and/or may pass int/string. Allowing int/string for flexibility of caller
	if n, ok := arg0.(float64); ok {
		toret.WriteString(strconv.Itoa(int(n)))
	} else if n, ok := arg0.(int); ok {
		toret.WriteString(strconv.Itoa(n))
	} else if n, ok := arg0.(string); ok {
		toret.WriteString(n)
	} else {
		return nil, fmt.Errorf("unexpected type %s", reflect.TypeOf(arg0))
	}

	for _, arg := range args[1:] {
		toret.WriteString(", ")

		switch t := arg.(type) {
		case string:
			if regex.MatchString(t) {
				toret.WriteString("'" + t + "'")
			} else {
				toret.WriteString(t)
			}
		default:
			return nil, fmt.Errorf("unexpected type %s", reflect.TypeOf(arg))
		}
	}

	return toret.String() + ")", nil

View on GitHub (pinned to 2736b63f8f)

Solutions

  1. Pass the threshold as int, float64, or a numeric string: OutOf(2, ...) or OutOf("2", ...).
  2. Convert other numeric types before the call, e.g. OutOf(int(n64), principals...).
  3. Check argument order — the threshold must be args[0], principals after it.
  4. If generated by code, add a type assertion/switch on the threshold value before invoking outof.

Example fix

// before
policydsl.OutOf(uint(2), "Org1.member") // uint is unsupported
// after
policydsl.OutOf(int(2), "Org1.member")
Defensive patterns

Strategy: type-guard

Validate before calling

switch t.(type) {
case int, float64, string:
	// ok
default:
	return fmt.Errorf("threshold must be int/float64/string, got %T", t)
}

Type guard

func isValidThreshold(v any) bool {
	switch v.(type) {
	case int, float64, string:
		return true
	}
	return false
}

Try / catch

_, err := policydsl.OutOf(threshold, principals...)
if err != nil && strings.Contains(err.Error(), "unexpected type") {
	return nil, fmt.Errorf("threshold %v (%T) is not numeric/string", threshold, threshold)
}

Prevention

When it happens

Trigger: Calling policydsl.OutOf(true, ...), OutOf(nil, ...), or OutOf(someStruct, ...) directly, or building gates programmatically where the threshold slot receives a non-numeric, non-string value.

Common situations: Passing an unsigned/int64/int32 threshold from config code without converting to int; accidentally swapping arguments so a principal struct lands in the threshold slot; using a *cb.SignaturePolicy where a number is expected.

Related errors


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