{"record":{"id":"6a4b0d5b61e47b98","repo":"hyperledger/fabric","slug":"not-in-the-channel","errorCode":null,"errorMessage":"not in the channel","messagePattern":"not in the channel","errorType":"exception","errorClass":"ErrNotInChannel","httpStatus":null,"severity":"critical","filePath":"orderer/common/cluster/deliver.go","lineNumber":641,"sourceCode":"\t\t\t},\n\t\t\tAtomicBroadcast_DeliverClient: stream,\n\t\t}, nil\n\t}\n}\n\ntype errorAndResponse struct {\n\terr  error\n\tresp *orderer.DeliverResponse\n}\n\n// ErrForbidden denotes that an ordering node refuses sending blocks due to access control.\nvar ErrForbidden = errors.New(\"forbidden pulling the channel\")\n\n// ErrServiceUnavailable denotes that an ordering node is not servicing at the moment.\nvar ErrServiceUnavailable = errors.New(\"service unavailable\")\n\n// ErrNotInChannel denotes that an ordering node is not in the channel\nvar ErrNotInChannel = errors.New(\"not in the channel\")\n\nvar ErrRetryCountExhausted = errors.New(\"retry attempts exhausted\")\n","sourceCodeStart":623,"sourceCodeEnd":644,"githubUrl":"https://github.com/hyperledger/fabric/blob/2736b63f8fd5932511d56fe68b7039d15977f7f6/orderer/common/cluster/deliver.go#L623-L644","documentation":"ErrNotInChannel is a sentinel meaning the ordering node is not a member of the channel. It is returned by detectSelfID when the node's certificate cannot be found among the channel's consenters, and by IsChannelMember/IsConsensusOfChannel-style checks (TestChainParticipant flow), so callers like the etcdraft consenter can detect self-removal (eviction).","triggerScenarios":"detectSelfID scans all consenters in the latest config block and finds no certificate matching the local node (consenter.go:115); TestChainParticipant returns it when probing reveals the node is not authorized; IsConsenterOfChannel fails to match the local cert.","commonSituations":"Node was voted out / removed from the consenter set via config update (Raft eviction); certificate rotation left stale certs in local config; channel name typo causing lookup against the wrong channel's consenter set.","solutions":["Fetch and inspect the latest config block to confirm whether the node's certificate is still in the consenter set","If removal was unintended, re-add the node via a channel config update signed by sufficient admins","If the node was legitimately evicted, stop its channel services or let the eviction suspicion mechanism halt the chain","Verify local TLS/orderer certificates match what is registered in the channel config"],"exampleFix":null,"handlingStrategy":"type-guard","validationCode":"if !nodeCertInConfigBlock(localCert, latestConfigBlock) { return cluster.ErrNotInChannel }","typeGuard":"func isNotInChannel(err error) bool { return errors.Is(err, cluster.ErrNotInChannel) }","tryCatchPattern":"id, err := detectSelfID(puller)\nif errors.Is(err, cluster.ErrNotInChannel) {\n    // local node evicted: halt chain / trigger eviction suspicion\n    return haltConsensus()\n}","preventionTips":["Diff the node's TLS cert against the consenter set after every config update","Handle ErrNotInChannel explicitly to self-halt when evicted","Keep certificate rotation coordinated with channel config updates","Verify channel names when constructing pullers"],"tags":["fabric","orderer","raft","consensus","eviction"],"backgroundTag":"node-not-in-channel","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"}