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

  1. Ensure the node joined the channel (JoinChan) before obtaining routing filters for it
  2. Verify the ChannelID bytes exactly match the channel name
  3. 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

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


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