hyperledger/fabric · error

Unknown id on checkACL %s

Error message

Unknown id on checkACL %s

What it means

In CheckACL, after resolving a policy, the identity payload must be one of the supported types (*pb.SignedProposal, *protoutil.SignedData, or []*protoutil.SignedData). Any other type falls to the default branch and returns 'Unknown id on checkACL'. The ACL checker cannot evaluate policy against that identity representation.

Source

Thrown at core/aclmgmt/defaultaclprovider.go:154

	}
	aclLogger.Debugw("Applying default access policy for resource", "channel", channelID, "policy", policy, "resource", resName)

	switch typedData := idinfo.(type) {
	case *pb.SignedProposal:
		return d.policyChecker.CheckPolicy(channelID, policy, typedData)
	case *common.Envelope:
		sd, err := protoutil.EnvelopeAsSignedData(typedData)
		if err != nil {
			return err
		}
		return d.policyChecker.CheckPolicyBySignedData(channelID, policy, sd)
	case *protoutil.SignedData:
		return d.policyChecker.CheckPolicyBySignedData(channelID, policy, []*protoutil.SignedData{typedData})
	case []*protoutil.SignedData:
		return d.policyChecker.CheckPolicyBySignedData(channelID, policy, typedData)
	default:
		aclLogger.Errorf("Unmapped id on checkACL %s", resName)
		return fmt.Errorf("Unknown id on checkACL %s", resName)
	}
}

// CheckACLNoChannel provides default behavior by mapping channelless resources to their ACL.
func (d *defaultACLProviderImpl) CheckACLNoChannel(resName string, idinfo any) error {
	policy := d.pResourcePolicyMap[resName]
	if policy == "" {
		aclLogger.Errorf("Unmapped channelless policy for %s", resName)
		return fmt.Errorf("Unmapped channelless policy for %s", resName)
	}

	switch typedData := idinfo.(type) {
	case *pb.SignedProposal:
		return d.policyChecker.CheckPolicyNoChannel(policy, typedData)
	case *common.Envelope:
		sd, err := protoutil.EnvelopeAsSignedData(typedData)
		if err != nil {
			return err

View on GitHub (pinned to 2736b63f8f)

Solutions

  1. Pass a *pb.SignedProposal for proposal-based checks or protoutil.SignedData / []*protoutil.SignedData for pre-extracted identities.
  2. For Envelope payloads use CheckACLNoChannel or convert the envelope into SignedData first.
  3. Inspect the caller to ensure it isn't forwarding a raw gRPC request object as idinfo.

Example fix

// before
aclProvider.CheckACL(resName, chID, envelope)
// after
sd := protoutil.NewSignedData(envelope.Payload, envelope.Signature, envelope.SignatureHeaderBytes? ) // or use proposal:
aclProvider.CheckACL(resName, chID, signedProposal)
Defensive patterns

Strategy: type-guard

Validate before calling

switch v := idinfo.(type) {
case *pb.SignedProposal, *protoutil.SignedData, []*protoutil.SignedData:
    // ok
default:
    return fmt.Errorf("CheckACL requires SignedProposal or SignedData, got %T", v)
}

Type guard

func isCheckableID(v any) bool {
    switch v.(type) {
    case *pb.SignedProposal, *protoutil.SignedData, []*protoutil.SignedData:
        return true
    }
    return false
}

Try / catch

if err := aclProvider.CheckACL(resName, channelID, idinfo); err != nil {
    if strings.HasPrefix(err.Error(), "Unknown id on checkACL") {
        return fmt.Errorf("wrap id as SignedProposal or SignedData before ACL check: %w", err)
    }
    return err
}

Prevention

When it happens

Trigger: Calling CheckACL with idinfo of an unexpected type — e.g. a *common.Envelope, *msp.SerializedIdentity, or a typed nil — through a custom peer extension or system chaincode that invokes the ACL provider directly.

Common situations: Custom service code ported from CheckACLNoChannel (which accepts Envelope) into channel-based CheckACL; wrapper code passing context values instead of SignedProposal/SignedData.

Related errors


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