{"record":{"id":"5c6dc1fe88ae1109","repo":"hyperledger/fabric","slug":"forbidden-pulling-the-channel","errorCode":null,"errorMessage":"forbidden pulling the channel","messagePattern":"forbidden pulling the channel","errorType":"exception","errorClass":"ErrForbidden","httpStatus":null,"severity":"error","filePath":"orderer/common/cluster/deliver.go","lineNumber":635,"sourceCode":"\t\t\tCertificate: cert,\n\t\t\twaitTimeout: waitTimeout,\n\t\t\t// The stream might be canceled while Close() is being called, but also\n\t\t\t// while a timeout expires, so ensure it's only called once.\n\t\t\tcancelFunc: func() {\n\t\t\t\tonce.Do(cancel)\n\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":617,"sourceCodeEnd":644,"githubUrl":"https://github.com/hyperledger/fabric/blob/2736b63f8fd5932511d56fe68b7039d15977f7f6/orderer/common/cluster/deliver.go#L617-L644","documentation":"ErrForbidden is a sentinel error returned when an ordering node refuses to send blocks due to access control — the Deliver RPC is authorized but the caller is not permitted to pull this channel. During endpoint probing, if every endpoint yields forbidden, the error is surfaced as the probe result so callers (like eviction detection) know the node was denied channel access.","triggerScenarios":"extractBlockFromResponse receives common.Status_FORBIDDEN; probeEndpoints/TestChainParticipant sees only FORBIDDEN errors from all endpoints and no healthy ones (deliver.go:362).","commonSituations":"A node's TLS certificate or ordering identity was removed/revoked from the channel (eviction scenario); channel membership changed via config update and the local node's certs no longer appear; pointing a node at a channel it never joined.","solutions":["Inspect the latest channel config block to see if the node's certificates are still consenter members","If the node was evicted, follow the eviction-suspection flow: pull the latest config block from another endpoint or genesis and rejoin the channel if intended","Re-add the node's certificate to the channel via a config update if membership is intended","Verify the correct channel name and TLS root CAs are used when creating the BlockPuller"],"exampleFix":null,"handlingStrategy":"type-guard","validationCode":"err := puller.TestChainParticipant()\nif errors.Is(err, cluster.ErrForbidden) { return fmt.Errorf(\"node lacks channel access; check consenter certs\") }","typeGuard":"func isForbidden(err error) bool { return errors.Is(err, cluster.ErrForbidden) }","tryCatchPattern":"err := puller.PullBlock(seq)\nif errors.Is(err, cluster.ErrForbidden) {\n    // node evicted or certs revoked: fetch latest config block via another endpoint\n    return handleEviction()\n}","preventionTips":["Verify node certificates are present in the channel config before starting services","Use the eviction suspicion flow to detect self-removal early","Keep channel membership and local node certs in sync after updates","Confirm channel name and TLS root CAs are correct"],"tags":["fabric","orderer","access-control","tls"],"backgroundTag":"channel-access-forbidden","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"}