hyperledger/fabric · error

expected at least two arguments to NOutOf. Given %d

Error message

expected at least two arguments to NOutOf. Given %d

What it means

policydsl.outof() builds the intermediate 'outof(t, ...)' string used to convert a policy DSL expression into a SignaturePolicy. It requires at least two arguments: the threshold t and at least one principal/policy. Fewer than two arguments means a t-out-of-n policy with no subjects, which is meaningless, so the library rejects it.

Source

Thrown at common/policydsl/policyparser.go:53

	RoleOrderer = "orderer"
)

var (
	regex = regexp.MustCompile(
		fmt.Sprintf("^([[:alnum:].-]+)([.])(%s|%s|%s|%s|%s)$",
			RoleAdmin, RoleMember, RoleClient, RolePeer, RoleOrderer),
	)
	regexErr = regexp.MustCompile("^No parameter '([^']+)' found[.]$")
)

// a stub function - it returns the same string as it's passed.
// 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) {

View on GitHub (pinned to 2736b63f8f)

Solutions

  1. Ensure OutOf is called with at least one subject: OutOf(t, principal1[, principal2...]).
  2. Check the policy string passed to FromString and add the missing principal(s), e.g. 'OutOf(1, "Org1.member")'.
  3. If principals are built dynamically, validate that the list is non-empty before calling OutOf; fall back to a default policy or return a config error.
  4. If you only need a single-subject policy, use SignedBy directly instead of OutOf.

Example fix

// before
policy, err := policydsl.FromString("OutOf(1)")
// after
policy, err := policydsl.FromString("OutOf(1, 'Org1.member')")
Defensive patterns

Strategy: validation

Validate before calling

func validateGateArgs(t any, principals ...string) error {
	if len(principals) < 1 {
		return fmt.Errorf("OutOf requires at least one principal")
	}
	return nil
}

Type guard

func hasMinArgs(args []any, n int) bool { return len(args) >= n }

Try / catch

policy, err := policydsl.FromString(spec)
if err != nil {
	if strings.Contains(err.Error(), "expected at least two arguments to NOutOf") {
		return nil, fmt.Errorf("policy %q has a gate with no subjects: %w", spec, err)
	}
	return nil, err
}

Prevention

When it happens

Trigger: Calling OutOf(t) with zero or one additional subject (e.g. OutOf(1) or OutOf()), or a policy string like 'OutOf(1)' evaluated via FromString so that and/or/outof receives fewer than 2 args.

Common situations: Hand-written policy strings missing subjects ('OutOf(2)') after an editor stripped a trailing principal; programmatic builders that append principals conditionally and end up empty (e.g. empty channel/application org list); typos like 'OutOf(2,)' that the expr parser drops.

Related errors


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