{"record":{"id":"f4394953737c4cca","repo":"hyperledger/fabric","slug":"access-denied","errorCode":null,"errorMessage":"access denied","messagePattern":"access denied","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"discovery/service.go","lineNumber":26,"sourceCode":"\nimport (\n\t\"bytes\"\n\t\"context\"\n\t\"encoding/hex\"\n\t\"fmt\"\n\n\t\"github.com/hyperledger/fabric-lib-go/common/flogging\"\n\t\"github.com/hyperledger/fabric-protos-go-apiv2/discovery\"\n\t\"github.com/hyperledger/fabric/common/util\"\n\t\"github.com/hyperledger/fabric/discovery/protoext\"\n\tcommon2 \"github.com/hyperledger/fabric/gossip/common\"\n\t\"github.com/hyperledger/fabric/protoutil\"\n\t\"github.com/pkg/errors\"\n)\n\nvar logger = flogging.MustGetLogger(\"discovery\")\n\nvar accessDenied = wrapError(errors.New(\"access denied\"))\n\n// certHashExtractor extracts the TLS certificate from a given context\n// and returns its hash\ntype certHashExtractor func(ctx context.Context) []byte\n\n// dispatcher defines a function that dispatches a query\ntype dispatcher func(q *discovery.Query) *discovery.QueryResult\n\ntype Service struct {\n\tconfig             Config\n\tchannelDispatchers map[protoext.QueryType]dispatcher\n\tlocalDispatchers   map[protoext.QueryType]dispatcher\n\tauth               *authCache\n\tSupport\n}\n\n// Config defines the configuration of the discovery service\ntype Config struct {","sourceCodeStart":8,"sourceCodeEnd":44,"githubUrl":"https://github.com/hyperledger/fabric/blob/2736b63f8fd5932511d56fe68b7039d15977f7f6/discovery/service.go#L8-L44","documentation":"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.","triggerScenarios":"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).","commonSituations":"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.","solutions":["Check the peer's discovery log for the warning line ('doesn't exist' vs 'isn't eligible') to learn the real cause","Verify the channel name and that the peer is joined to it (peer channel list)","Configure discovery.authCacheEnabled/authenticator so the client's TLS cert is recognized, and send the correct client cert hash in the request","Regenerate/rotate client TLS certificates and retry; ensure core.yaml discovery settings match your deployment"],"exampleFix":"// before\nclient.Discover(ctx, channel=\"mychan\") // peer not joined\n// after\npeer channel join --channelID mychannel\nclient.Discover(ctx, channel=\"mychannel\")","handlingStrategy":"try-catch","validationCode":"channels, err := clientForPeer.DiscoverChannels(ctx)\nif err != nil || !containsChannel(channels, targetChannel) {\n  return fmt.Errorf(\"peer not joined to %s\", targetChannel)\n}","typeGuard":null,"tryCatchPattern":"peers, err := client.PeersForEndorsement(ctx, req)\nif err != nil && strings.Contains(err.Error(), \"access denied\") {\n  // check peer discovery logs for 'doesn't exist' vs 'isn't eligible';\n  // fix channel name or TLS client cert, then retry\n}","preventionTips":["Verify channel names against peer channel list","Keep discovery TLS client certificate configuration in sync with cert rotation","Send channel-less queries only where the server's auth config permits them"],"tags":["fabric","discovery","access-denied","tls","authorization"],"backgroundTag":"access-denied","analyzedSha":"2736b63f8fd5932511d56fe68b7039d15977f7f6","analyzedAt":"2026-09-04T08:52:36.465Z","contentChangedAt":"2026-09-04T08:52:36.465Z","schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}