hyperledger/fabric · error
Channel %s doesn't exist
Error message
Channel %s doesn't exist
What it means
Node.PeerFilter looks up the gossip channel for the given chain ID and returns this error wrapped via errors.Errorf when the channel is unknown. Routing filters need channel-scoped membership, so a missing channel means no valid filter can be produced.
Source
Thrown at gossip/gossip/gossip_impl.go:762
func (g *Node) SelfMembershipInfo() discovery.NetworkMember {
return g.disc.Self()
}
// SelfChannelInfo returns the peer's latest StateInfo message of a given channel
func (g *Node) SelfChannelInfo(chain common.ChannelID) *protoext.SignedGossipMessage {
ch := g.chanState.getGossipChannelByChainID(chain)
if ch == nil {
return nil
}
return ch.Self()
}
// PeerFilter receives a SubChannelSelectionCriteria and returns a RoutingFilter that selects
// only peer identities that match the given criteria, and that they published their channel participation
func (g *Node) PeerFilter(channel common.ChannelID, messagePredicate api.SubChannelSelectionCriteria) (filter.RoutingFilter, error) {
gc := g.chanState.getGossipChannelByChainID(channel)
if gc == nil {
return nil, errors.Errorf("Channel %s doesn't exist", channel)
}
return gc.PeerFilter(messagePredicate), nil
}
// Stop stops the gossip component
func (g *Node) Stop() {
if g.toDie() {
return
}
atomic.StoreInt32(&g.stopFlag, int32(1))
g.logger.Info("Stopping gossip")
close(g.toDieChan)
g.stopSignal.Wait()
g.chanState.stop()
g.discAdapter.close()
g.disc.Stop()
g.certStore.stop()
g.emitter.Stop()View on GitHub (pinned to 2736b63f8f)
Solutions
- Ensure the node joined the channel (JoinChan) before obtaining routing filters for it
- Verify the ChannelID bytes exactly match the channel name
- Handle the error by skipping/requeueing the message rather than treating it as fatal
Example fix
// before
filter, err := g.PeerFilter(channel, predicate)
filter(...)
// after
filter, err := g.PeerFilter(channel, predicate)
if err != nil {
// channel doesn't exist; skip routing for this channel
return
}
filter(...) Defensive patterns
Strategy: try-catch
Validate before calling
// check channel presence first
if g.chanState.getGossipChannelByChainID(channel) == nil {
return nil, fmt.Errorf("channel %s not joined", channel)
}
f, err := g.PeerFilter(channel, predicate) Try / catch
f, err := g.PeerFilter(channel, predicate)
if err != nil {
logger.Debugf("no filter for channel %s: %v", channel, err)
return nil // skip routing
} Prevention
- Join the channel before building routing filters for it
- Treat unknown-channel errors as skip signals in message handlers
- Keep channel lifecycle (join/stop) synchronized with message routing code
When it happens
Trigger: Calling PeerFilter (via computeFilters or getMatchAllRoutingFilter paths) with a common.ChannelID the local gossip node hasn't joined, or after the channel was removed from chanState.
Common situations: Pull/state message routing on channels that were stopped or never joined; channel ID typos; race where a channel is removed while message handlers still reference it.
Related errors
- requested to Send for channel %s, but no such channel exists
- Could not acquire policy manager for channel %s
- specified --channelID %s does not match channel ID %s in con
- specified --channelID %s does not match channel ID %s in con
- could not get msp for channel [%s]
AI-assisted analysis of hyperledger/fabric@2736b63f8f (2026-09-04).
Data as JSON: /api/errors/a4e8bc12c2f08dc3.
Report an issue: GitHub.