hyperledger/fabric · error

access denied

Error message

access denied

What it means

The discovery service returns the sentinel accessDenied error for any query whose channel doesn't exist locally or whose client identity isn't eligible for discovery service on that channel (TLS/client cert checks in the auth filter). It is a deliberate opaque denial: the server logs the real reason but tells the client only 'access denied' so discovery doesn't leak channel information.

Source

Thrown at discovery/service.go:26

import (
	"bytes"
	"context"
	"encoding/hex"
	"fmt"

	"github.com/hyperledger/fabric-lib-go/common/flogging"
	"github.com/hyperledger/fabric-protos-go-apiv2/discovery"
	"github.com/hyperledger/fabric/common/util"
	"github.com/hyperledger/fabric/discovery/protoext"
	common2 "github.com/hyperledger/fabric/gossip/common"
	"github.com/hyperledger/fabric/protoutil"
	"github.com/pkg/errors"
)

var logger = flogging.MustGetLogger("discovery")

var accessDenied = wrapError(errors.New("access denied"))

// certHashExtractor extracts the TLS certificate from a given context
// and returns its hash
type certHashExtractor func(ctx context.Context) []byte

// dispatcher defines a function that dispatches a query
type dispatcher func(q *discovery.Query) *discovery.QueryResult

type Service struct {
	config             Config
	channelDispatchers map[protoext.QueryType]dispatcher
	localDispatchers   map[protoext.QueryType]dispatcher
	auth               *authCache
	Support
}

// Config defines the configuration of the discovery service
type Config struct {

View on GitHub (pinned to 2736b63f8f)

Solutions

  1. Check the peer's discovery log for the warning line ('doesn't exist' vs 'isn't eligible') to learn the real cause
  2. Verify the channel name and that the peer is joined to it (peer channel list)
  3. Configure discovery.authCacheEnabled/authenticator so the client's TLS cert is recognized, and send the correct client cert hash in the request
  4. Regenerate/rotate client TLS certificates and retry; ensure core.yaml discovery settings match your deployment

Example fix

// before
client.Discover(ctx, channel="mychan") // peer not joined
// after
peer channel join --channelID mychannel
client.Discover(ctx, channel="mychannel")
Defensive patterns

Strategy: try-catch

Validate before calling

channels, err := clientForPeer.DiscoverChannels(ctx)
if err != nil || !containsChannel(channels, targetChannel) {
  return fmt.Errorf("peer not joined to %s", targetChannel)
}

Try / catch

peers, err := client.PeersForEndorsement(ctx, req)
if err != nil && strings.Contains(err.Error(), "access denied") {
  // check peer discovery logs for 'doesn't exist' vs 'isn't eligible';
  // fix channel name or TLS client cert, then retry
}

Prevention

When it happens

Trigger: processQuery receives a query with a Channel that s.ChannelExists doesn't know (client asking about a channel the peer isn't joined to), or s.auth.EligibleForService fails (client TLS cert not among discovery.authenticator clientCertRefs, wrong TLS material, or channel-less query when TLS disallows it).

Common situations: Typo'd or nonexistent channel name; peer not joined to the channel; client not presenting the expected TLS certificate (discovery.authTLSasCertHash / clientCertHashRef misconfig); using channel-less discovery queries when service requires a channel; stale TLS certs after rotation.

Understand the failure class

Related errors


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