hyperledger/fabric · error

subpolicy number %d type %T of policy %s is not convertible

Error message

subpolicy number %d type %T of policy %s is not convertible

What it means

ImplicitMetaPolicy.Convert walks its subpolicies and requires each one to implement the Converter interface. If a subpolicy is of a type that cannot be converted (e.g. a raw SignaturePolicy or an unimplemented policy type), conversion aborts with this error naming the index, dynamic type, and policy name.

Source

Thrown at common/policies/convert.go:117

	converted := &cb.SignaturePolicyEnvelope{
		Version: 0,
		Rule: &cb.SignaturePolicy{
			Type: &cb.SignaturePolicy_NOutOf_{
				NOutOf: &cb.SignaturePolicy_NOutOf{
					N: int32(p.Threshold),
				},
			},
		},
	}

	// the conversion approach for an implicit meta
	// policy is to convert each of the subpolicies,
	// merge it with the previous one and return the
	// merged policy
	for i, subPolicy := range p.SubPolicies {
		convertibleSubpolicy, ok := subPolicy.(Converter)
		if !ok {
			return nil, errors.Errorf("subpolicy number %d type %T of policy %s is not convertible", i, subPolicy, p.SubPolicyName)
		}

		spe, err := convertibleSubpolicy.Convert()
		if err != nil {
			return nil, errors.WithMessagef(err, "failed to convert subpolicy number %d of policy %s", i, p.SubPolicyName)
		}

		merge(converted, spe)
	}

	return converted, nil
}

View on GitHub (pinned to 2736b63f8f)

Solutions

  1. Fix the channel configuration so each subpolicy of the implicit meta policy is itself an ImplicitMetaPolicy (convertible)
  2. Inspect the %T in the error to identify the offending subpolicy type and correct its configtx entry
  3. Validate the channel config (configtxgen / configtxlator) before submitting the update
  4. If receiving this from a peer, reject/fix the offending channel creation or update transaction

Example fix

# before (configtx.yaml)
Policy: OR("Admins")          # becomes a signature policy subpolicy
# after
Policies:
  Readers:
    Type: ImplicitMeta
    Rule: "ANY Readers"        # nested implicit-meta subpolicies only
Defensive patterns

Strategy: validation

Validate before calling

func subPoliciesConvertible(cfg *cb.ConfigGroup) error {
	for name, p := range cfg.Policies {
		imp := &cb.ImplicitMetaPolicy{}
		if err := proto.Unmarshal(p.Policy.Value, imp); err == nil {
			for _, sp := range imp.SubPolicies {
				if _, ok := sp.(policies.Converter); !ok {
					return fmt.Errorf("subpolicy %s of %s is not convertible (%T)", name, name, sp)
				}
			}
		}
	}
	return nil
}

Type guard

func isConvertibleSubpolicy(sp interface{}) bool {
	_, ok := sp.(policies.Converter)
	return ok
}

Try / catch

converted, err := impPolicy.Convert()
if err != nil {
	if strings.Contains(err.Error(), "is not convertible") {
		log.Errorf("fix channel config: %v", err) // correct the offending subpolicy type in configtx
	}
	return err
}

Prevention

When it happens

Trigger: Calling Convert() on an ImplicitMetaPolicy whose config proto contains subpolicies that are not convertible — e.g. a channel config policy built with a SignaturePolicyEnvelope instead of another ImplicitMetaPolicy, or an unknown policy type injected via malformed channel creation/update config.

Common situations: Mis-authored configtx.yaml where a nested policy is a signature policy rather than an implicit meta policy; malformed channel update transactions; proto payloads deserialized into unexpected types; tests like TestImplicitMetaPolicy_Convert* exercising bad subpolicy types.

Related errors


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