{"record":{"id":"10a8f6758b44c914","repo":"hyperledger/fabric","slug":"block-deliverer-for-channel-s-is-already-stoppe","errorCode":null,"errorMessage":"block deliverer for channel `%s` is already stopped","messagePattern":"block deliverer for channel `(.+?)` is already stopped","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"core/deliverservice/deliveryclient.go","lineNumber":304,"sourceCode":"\t\t\treturn nil, fmt.Errorf(\"failed to access client TLS configuration: %w\", err)\n\t\t}\n\t\tdcBFT.TLSCertHash = util.ComputeSHA256(cert.Certificate[0])\n\t}\n\n\tdcBFT.Initialize(d.conf.ChannelConfig, \"\")\n\n\treturn dcBFT, nil\n}\n\n// StopDeliverForChannel stops blocks delivery for channel by stopping channel block provider\nfunc (d *deliverServiceImpl) StopDeliverForChannel() error {\n\td.lock.Lock()\n\tdefer d.lock.Unlock()\n\n\tif d.stopping {\n\t\terrMsg := fmt.Sprintf(\"block deliverer for channel `%s` is already stopped\", d.channelID)\n\t\tlogger.Errorf(\"Delivery service: %s\", errMsg)\n\t\treturn errors.New(errMsg)\n\t}\n\n\tif d.blockDeliverer == nil {\n\t\terrMsg := fmt.Sprintf(\"block deliverer for channel `%s` is <nil>, can't stop delivery\", d.channelID)\n\t\tlogger.Errorf(\"Delivery service: %s\", errMsg)\n\t\treturn errors.New(errMsg)\n\t}\n\td.blockDeliverer.Stop()\n\td.blockDeliverer = nil\n\n\tlogger.Debugf(\"This peer will stop passing blocks from orderer service to other peers on channel: %s\", d.channelID)\n\treturn nil\n}\n\n// Stop all service and release resources\nfunc (d *deliverServiceImpl) Stop() {\n\td.lock.Lock()\n\tdefer d.lock.Unlock()","sourceCodeStart":286,"sourceCodeEnd":322,"githubUrl":"https://github.com/hyperledger/fabric/blob/2736b63f8fd5932511d56fe68b7039d15977f7f6/core/deliverservice/deliveryclient.go#L286-L322","documentation":"StopDeliverForChannel returns this error when the channel's block deliverer has already entered the stopping state (d.stopping is true under the service lock). It is a guard against double-stop of the delivery service for a channel, not a malfunction.","triggerScenarios":"Calling StopDeliverForChannel(channelID) twice for the same channel, or calling it after Stop()/stopping was already initiated (e.g. during peer shutdown or previous stop attempt).","commonSituations":"Application or lifecycle code invoking stop-delivery in both a shutdown hook and an error-handling path; reconnection logic stopping a channel that the service is concurrently stopping; duplicate channel close events.","solutions":["Treat this error as benign and idempotent — check for the 'already stopped' message and ignore it","Track stop state on the caller side so StopDeliverForChannel is invoked once per channel","Synchronize concurrent stop calls so only one goroutine stops a given channel","If the channel should be usable again, restart delivery via StartDeliverForChannel instead of re-stopping"],"exampleFix":"// before\nerr := deliverService.StopDeliverForChannel(ch)\nif err != nil { return err }\n// after\nerr := deliverService.StopDeliverForChannel(ch)\nif err != nil && strings.Contains(err.Error(), \"already stopped\") {\n    return nil // idempotent stop\n}\nif err != nil { return err }","handlingStrategy":"try-catch","validationCode":"// check state before calling stop, if exposed by your wrapper\nif tracker.IsStopping(channelID) {\n    return nil\n}","typeGuard":"func isAlreadyStopped(err error) bool {\n    return err != nil && strings.Contains(err.Error(), \"is already stopped\")\n}","tryCatchPattern":"if err := svc.StopDeliverForChannel(ch); err != nil {\n    if isAlreadyStopped(err) {\n        return nil // idempotent\n    }\n    return err\n}","preventionTips":["Make stop operations idempotent in your orchestration code","Guard with a per-channel mutex around start/stop calls","Invoke stop from a single shutdown path, not multiple hooks"],"tags":["lifecycle","double-stop","hyperledger-fabric"],"backgroundTag":"already-stopped","analyzedSha":"2736b63f8fd5932511d56fe68b7039d15977f7f6","analyzedAt":"2026-09-04T08:52:36.465Z","contentChangedAt":"2026-09-04T08:52:36.465Z","schemaVersion":2},"datasetVersion":"2026-09-08T15:18:49.778Z"}