hyperledger/fabric · error

policy %s at path %s was nil

Error message

policy %s at path %s was nil

What it means

NewManagerImpl builds the runtime policy map from the config tree. If a configured policy entry exists but its embedded Policy proto is nil, the manager cannot construct it and throws this error naming the policy and its config path.

Source

Thrown at common/policies/policy.go:205

	_, ok := providers[int32(cb.Policy_IMPLICIT_META)]
	if ok {
		logger.Panicf("ImplicitMetaPolicy type must be provider by the policy manager")
	}

	managers := make(map[string]*ManagerImpl)

	for groupName, group := range root.Groups {
		managers[groupName], err = NewManagerImpl(path+PathSeparator+groupName, providers, group)
		if err != nil {
			return nil, err
		}
	}

	policies := make(map[string]Policy)
	for policyName, configPolicy := range root.Policies {
		policy := configPolicy.Policy
		if policy == nil {
			return nil, fmt.Errorf("policy %s at path %s was nil", policyName, path)
		}

		var cPolicy Policy

		if policy.Type == int32(cb.Policy_IMPLICIT_META) {
			imp, err := NewImplicitMetaPolicy(policy.Value, managers)
			if err != nil {
				return nil, errors.Wrapf(err, "implicit policy %s at path %s did not compile", policyName, path)
			}
			cPolicy = imp
		} else {
			provider, ok := providers[policy.Type]
			if !ok {
				return nil, fmt.Errorf("policy %s at path %s has unknown policy type: %v", policyName, path, policy.Type)
			}

			var err error
			cPolicy, _, err = provider.NewPolicy(policy.Value)

View on GitHub (pinned to 2736b63f8f)

Solutions

  1. Populate the Policy field (type and value) for the named policy in the config
  2. Regenerate the channel configuration with a correct configtx.yaml profile so every policy entry has a body
  3. Remove the empty policy entry if it is not needed

Example fix

// before
&cb.ConfigPolicy{Policy: nil}
// after
&cb.ConfigPolicy{Policy: &cb.Policy{Type: int32(cb.Policy_IMPLICIT_META), Value: "ANY Readers"}}
Defensive patterns

Strategy: validation

Validate before calling

for name, cp := range configGroup.Policies {
  if cp == nil || cp.Policy == nil {
    return fmt.Errorf("policy %s has no Policy proto defined", name)
  }
}

Try / catch

mgr, err := policies.NewManagerImpl(root, path, providers)
if err != nil && strings.Contains(err.Error(), "was nil") {
  return fmt.Errorf("channel config contains an empty policy entry: %w", err)
}

Prevention

When it happens

Trigger: Calling NewManagerImpl (directly or via NewBundle) on a config tree where root.Policies contains an entry whose Policy field was never populated, e.g. a placeholder policy group created but not assigned a policy proto.

Common situations: Hand-edited or tool-generated channel config with an empty policy entry; an update transaction that removed the policy body but left the key; configtx template producing an empty policy stanza.

Related errors


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