{"record":{"id":"4c8a6d37cc671276","repo":"hyperledger/fabric","slug":"chain-is-stopped","errorCode":null,"errorMessage":"chain is stopped","messagePattern":"chain is stopped","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"orderer/consensus/etcdraft/chain.go","lineNumber":423,"sourceCode":"// Configure submits config type transactions for ordering.\nfunc (c *Chain) Configure(env *common.Envelope, configSeq uint64) error {\n\tc.Metrics.ConfigProposalsReceived.Add(1)\n\treturn c.Submit(&orderer.SubmitRequest{LastValidationSeq: configSeq, Payload: env, Channel: c.channelID}, 0)\n}\n\n// WaitReady blocks when the chain:\n// - is catching up with other nodes using snapshot\n//\n// In any other case, it returns right away.\nfunc (c *Chain) WaitReady() error {\n\tif err := c.isRunning(); err != nil {\n\t\treturn err\n\t}\n\n\tselect {\n\tcase c.submitC <- nil:\n\tcase <-c.doneC:\n\t\treturn errors.Errorf(\"chain is stopped\")\n\t}\n\n\treturn nil\n}\n\n// Errored returns a channel that closes when the chain stops.\nfunc (c *Chain) Errored() <-chan struct{} {\n\tc.errorCLock.RLock()\n\tdefer c.errorCLock.RUnlock()\n\treturn c.errorC\n}\n\n// Halt stops the chain.\nfunc (c *Chain) Halt() {\n\tc.stop()\n}\n\nfunc (c *Chain) stop() bool {","sourceCodeStart":405,"sourceCodeEnd":441,"githubUrl":"https://github.com/hyperledger/fabric/blob/2736b63f8fd5932511d56fe68b7039d15977f7f6/orderer/consensus/etcdraft/chain.go#L405-L441","documentation":"WaitReady blocks until the chain can accept an operation by sending a nil onto submitC; if the chain has already stopped (doneC closed), the select picks doneC and returns 'chain is stopped'. Callers use it to wait for the chain to be ready to process requests, and this error tells them the chain is permanently halted.","triggerScenarios":"Calling Chain.WaitReady (e.g., before Submit on the broadcast/deliver path) after the raft chain has halted — due to fatal errors, being removed from the channel, config-driven halting, or Orderer shutdown.","commonSituations":"Clients submitting transactions while the orderer is shutting down; the node cowardly halting after detecting a wrong raft ID (out-of-date certificate); channel removal triggering chain stop while traffic is in flight.","solutions":["Detect the stopped chain and re-route submissions to another orderer in the consenter set.","Check orderer logs for the reason the chain halted (e.g., 'Cowardly halting', channel removed) and fix the root cause.","If the node's TLS/consenter certs were rotated, update the channel config and restart the orderer with correct certs so it can rejoin.","If the channel was removed, re-join it via the participation API to restart the chain."],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"select {\ncase <-chain.Errored():\n    // chain stopped; route work to another orderer\n    return\ndefault:\n    if err := chain.WaitReady(); err != nil {\n        if strings.Contains(err.Error(), \"chain is stopped\") {\n            failoverToAnotherOrderer()\n        }\n    }\n}","preventionTips":["Check chain.Errored() before submitting during shutdown","Handle halts (cert rotation, channel removal) promptly","Load-balance submissions across multiple orderers"],"tags":["orderer","etcdraft","raft","lifecycle"],"backgroundTag":"chain-stopped","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"}