hyperledger/fabric · error

channel %s doesn't exist

Error message

channel %s doesn't exist

What it means

requestContext successfully extracted a channel name from the message, but c.Chan2Members contains no membership mapping for that channel. The orderer's cluster communication layer only knows about channels it is a member of; a message referencing an unknown channel cannot be attributed to a valid member set, so it is rejected.

Source

Thrown at orderer/common/cluster/comm.go:98

		return err
	}
	return c.H.OnConsensus(reqCtx.channel, reqCtx.sender, request)
}

// requestContext identifies the sender and channel of the request and returns
// it wrapped in a requestContext
func (c *Comm) requestContext(ctx context.Context, msg proto.Message) (*requestContext, error) {
	channel := c.ChanExt.TargetChannel(msg)
	if channel == "" {
		return nil, errors.Errorf("badly formatted message, cannot extract channel")
	}

	c.Lock.RLock()
	mapping, exists := c.Chan2Members[channel]
	c.Lock.RUnlock()

	if !exists {
		return nil, errors.Errorf("channel %s doesn't exist", channel)
	}

	cert := util.ExtractRawCertificateFromContext(ctx)
	if len(cert) == 0 {
		return nil, errors.Errorf("no TLS certificate sent")
	}

	stub := mapping.LookupByClientCert(cert)
	if stub == nil {
		return nil, errors.Errorf("certificate extracted from TLS connection isn't authorized")
	}
	return &requestContext{
		channel: channel,
		sender:  stub.ID,
	}, nil
}

// Remote obtains a RemoteContext linked to the destination node on the context

View on GitHub (pinned to 2736b63f8f)

Solutions

  1. Verify this orderer actually belongs to the named channel (check channel participation / genesis block configuration)
  2. Ensure the channel config update that added this orderer was committed and the orderer pulled it
  3. Check the sender's channel name spelling and that it targets the correct channel
  4. Restart the orderer after channel creation so Chan2Members is repopulated from the ledger

Example fix

// before (sender sends for a channel the orderer isn't part of)
clusterClient.Step(ctx, makeEnvelope("channel-unknown", msg))
// after — verify channel membership first
if ordererIsMemberOf("mychannel") {
    clusterClient.Step(ctx, makeEnvelope("mychannel", msg))
}
Defensive patterns

Strategy: validation

Validate before calling

// Sender-side: only dispatch to channels the target orderer belongs to
if _, err := os.Stat(channelLedgerPath(targetOrderer, channelName)); err != nil {
    return fmt.Errorf("orderer %s is not a member of channel %s", targetOrderer, channelName)
}
// Receiver-side guard: check channel participation before Step
curl -s http://orderer:8443/participation/v1/channels | jq '.channels[].name'

Prevention

When it happens

Trigger: DispatchSubmit or DispatchConsensus delivers a message whose channel header names a channel this orderer has no mapping for — e.g. the channel was never joined, was removed, or the channel name is misspelled by the sender.

Common situations: An orderer added to a channel without the config update reaching it; sender and receiver disagree on channel name due to config drift; stale nodes sending traffic for deleted channels; genesis/system channel differences after upgrades.

Related errors


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