{"record":{"id":"a2007f8b607deebe","repo":"chenhg5/cc-connect","slug":"webex-platform-stopped","errorCode":null,"errorMessage":"webex: platform stopped","messagePattern":"webex: platform stopped","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"platform/webex/webex.go","lineNumber":202,"sourceCode":"func (p *Platform) isStopping() bool {\n\tp.mu.RLock()\n\tdefer p.mu.RUnlock()\n\treturn p.stopping\n}\n\nconst (\n\tinitialBackoff   = time.Second\n\tmaxBackoff       = 30 * time.Second\n\tstableConnWindow = 10 * time.Second\n)\n\n// Start fetches the bot identity, registers a device, and launches the\n// reconnecting WebSocket read loop in the background.\nfunc (p *Platform) Start(handler core.MessageHandler) error {\n\tp.mu.Lock()\n\tif p.stopping {\n\t\tp.mu.Unlock()\n\t\treturn fmt.Errorf(\"webex: platform stopped\")\n\t}\n\tp.handler = handler\n\tctx, cancel := context.WithCancel(context.Background())\n\tp.cancel = cancel\n\tp.mu.Unlock()\n\n\tme, err := p.client.GetMe(ctx)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"webex: getMe: %w\", err)\n\t}\n\tp.mu.Lock()\n\tp.selfID = me.ID\n\tif len(me.Emails) > 0 {\n\t\tp.selfEmail = me.Emails[0]\n\t}\n\tp.mu.Unlock()\n\tslog.Info(\"webex: authenticated\", \"bot\", me.DisplayName)\n","sourceCodeStart":184,"sourceCodeEnd":220,"githubUrl":"https://github.com/chenhg5/cc-connect/blob/4000b2338aa6e850c99df54f8b0ed6ed7460b401/platform/webex/webex.go#L184-L220","documentation":"Start refuses to begin if the platform is already shutting down (p.stopping is set under the mutex). This prevents resurrecting a platform after Stop was called. It is a lifecycle state guard, not a network error.","triggerScenarios":"Calling Start after Stop (or during shutdown) on the same Platform instance; concurrent Start racing with a Stop that already set p.stopping=true.","commonSituations":"Restart logic that reuses a stopped Platform object instead of constructing a new one via New; daemon reload handlers calling Start during teardown.","solutions":["Construct a fresh Platform via New(opts) instead of calling Start on a stopped instance","Serialize lifecycle calls: ensure Stop completes before any new Start, and never call Start concurrently with Stop","Restructure reconnect/restart logic to operate inside the platform's own reconnect loop rather than re-calling Start","Check application shutdown sequencing so Start isn't invoked after the daemon initiated teardown"],"exampleFix":"// before\np.Stop()\np.Start(handler) // panics with \"platform stopped\"\n// after\np.Stop()\np2, err := webex.New(opts)\nif err != nil { return err }\np2.Start(handler)","handlingStrategy":"try-catch","validationCode":"// do not call Start on a platform whose Stop has been invoked; track lifecycle state\nif platformStopped { return errors.New(\"platform already stopped; construct a new one\") }","typeGuard":null,"tryCatchPattern":"if err := p.Start(handler); err != nil {\n    if strings.Contains(err.Error(), \"platform stopped\") {\n        return fmt.Errorf(\"create a new platform instance instead of restarting\")\n    }\n    return err\n}","preventionTips":["Treat platforms as single-use: New → Start → Stop, never Stop → Start","Serialize lifecycle transitions behind a mutex or lifecycle manager","Move reconnection into the platform's internal loop instead of external Start calls","Review daemon shutdown/reload ordering"],"tags":["webex","lifecycle","shutdown","state"],"backgroundTag":"invalid-state-transition","analyzedSha":"4000b2338aa6e850c99df54f8b0ed6ed7460b401","analyzedAt":"2026-09-06T11:45:09.575Z","contentChangedAt":"2026-09-06T11:45:09.575Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}