hyperledger/fabric · error

ErrChannelNotReady

ErrChannelNotReady

Error message

channel is not ready, he is a follower

What it means

ErrChannelNotReady is returned by the channel participation API when an update is attempted on a channel whose local node is a follower in the consortium rather than a fully-started (active) participant. In Hyperledger Fabric's channel participation, only channels in the 'active' state can accept configuration updates via the REST API; follower channels are passively replicating and reject mutations. The error surfaces as HTTP 403 Forbidden from the UpdateChannel REST handler.

Solutions

  1. Wait until the channel status becomes 'active' (check GET /participation/v1/channels/{channelID}) before issuing the update.
  2. Verify the node was properly added as a consenter and that the join (or snapshot restore) completed; re-join the channel if it is stuck in follower state.
  3. Ensure the config update is submitted to a node that is active in the channel, not a follower-only node.
  4. If the channel is pending removal or stuck, remove and re-join the channel via the participation API.

Example fix

// before: update immediately after join, channel still follower
info, err := manager.UpdateChannel(channelID, envelope)

// after: poll until active, then update
for {
    info, _ := manager.FetchChannel(channelID)
    if info.Status == types.StatusActive { break }
    time.Sleep(time.Second)
}
info, err := manager.UpdateChannel(channelID, envelope)
Defensive patterns

Strategy: validation

Validate before calling

info, err := manager.FetchChannel(channelID)
if err != nil { return err }
if info.Status != types.StatusActive {
    return fmt.Errorf("channel %s not active (status=%s), refusing update", channelID, info.Status)
}

Type guard

func channelReadyForUpdate(info types.ChannelInfo) bool {
    return info.Status == types.StatusActive
}

Prevention

When it happens

Trigger: Calling the channel participation REST API PUT /participation/v1/channels/{channelID} (UpdateChannel) when the channel's local state is 'follower' rather than 'active'. Also occurs in FetchBlock and sendUpdateError paths when the registrar reports the channel as a follower.

Common situations: An operator joins a channel with joinBySnapshot or as a follower before the node has caught up / been promoted to active, then tries to push a config update. Common after node restart before catch-up, or when updating a channel on a node that joined but never became a consenter/active member.

Related errors


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

Appendix: source

Thrown at orderer/common/types/errors.go:37

// ErrChannelAlreadyExists is returned when trying to join a app channel that already exists (when the system channel does not
// exist), or when trying to join the system channel when it already exists.
var ErrChannelAlreadyExists = errors.New("channel already exists")

// ErrAppChannelsAlreadyExists is returned when trying to join a system channel (that does not exist) when application channels
// already exist.
var ErrAppChannelsAlreadyExists = errors.New("application channels already exist")

// ErrChannelNotExist is returned when trying to remove or list a channel that does not exist
var ErrChannelNotExist = errors.New("channel does not exist")

// ErrChannelPendingRemoval is returned when trying to remove or list a channel that is being removed.
var ErrChannelPendingRemoval = errors.New("channel pending removal")

// ErrChannelRemovalFailure is returned when a removal attempt failure has been recorded.
var ErrChannelRemovalFailure = errors.New("channel removal failure")

// ErrChannelNotReady is returned when trying to update a channel that is a follower
var ErrChannelNotReady = errors.New("channel is not ready, he is a follower")

View on GitHub (pinned to 2736b63f8f)