{"record":{"id":"629319515e38d1b9","repo":"chenhg5/cc-connect","slug":"max-platform-stopped","errorCode":null,"errorMessage":"max: platform stopped","messagePattern":"max: platform stopped","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"platform/max/max.go","lineNumber":159,"sourceCode":"\t\tallowFrom:           allowFrom,\n\t\twebhookURL:          webhookURL,\n\t\twebhookListen:       webhookListen,\n\t\twebhookPath:         webhookPath,\n\t\twebhookSecret:       webhookSecret,\n\t\tresubscribeInterval: resubscribeInterval,\n\t\tclient:              &http.Client{Timeout: httpTimeout},\n\t\tuploadClient:        &http.Client{Timeout: attachmentUploadTO},\n\t}, nil\n}\n\nfunc (p *Platform) Name() string { return \"max\" }\n\nfunc (p *Platform) Start(handler core.MessageHandler) error {\n\tp.mu.Lock()\n\tdefer p.mu.Unlock()\n\n\tif p.stopping {\n\t\treturn fmt.Errorf(\"max: platform stopped\")\n\t}\n\tp.handler = handler\n\n\tctx, cancel := context.WithCancel(context.Background())\n\tp.ctx = ctx\n\tp.cancel = cancel\n\n\t// Verify token at startup\n\tif name, id, err := p.getMe(ctx); err != nil {\n\t\tslog.Warn(\"max: could not verify bot token\", \"error\", err)\n\t} else {\n\t\tslog.Info(\"max: connected\", \"bot\", name, \"id\", id)\n\t}\n\n\tif p.webhookURL != \"\" {\n\t\tif err := p.startWebhook(ctx); err != nil {\n\t\t\tcancel()\n\t\t\treturn fmt.Errorf(\"max: start webhook: %w\", err)","sourceCodeStart":141,"sourceCodeEnd":177,"githubUrl":"https://github.com/chenhg5/cc-connect/blob/4000b2338aa6e850c99df54f8b0ed6ed7460b401/platform/max/max.go#L141-L177","documentation":"Start refuses to start the platform if p.stopping is set, i.e. the platform is in the middle of shutting down. This guards against racing a Start call against Stop and returning a half-started platform.","triggerScenarios":"Calling Start(handler) after Stop() has been called (or while Stop is still running) on the same *Platform instance.","commonSituations":"Restart logic that reuses the old Platform object instead of constructing a new one via New; lifecycle races between a shutdown signal handler and a reconnect loop calling Start concurrently.","solutions":["Create a fresh Platform via New() and call Start on it instead of reusing a stopped instance.","Ensure Stop() fully completes before calling Start, e.g. wait for Stop's goroutine/WaitGroup.","Add synchronization so Start and Stop cannot run concurrently on the same instance."],"exampleFix":"// before\np.Stop()\np.Start(handler) // error: platform stopped\n// after\np.Stop()\np = max.New(opts)\np.Start(handler)","handlingStrategy":"try-catch","validationCode":"if p.isStopped() { return errors.New(\"platform already stopped; create a new instance\") }","typeGuard":null,"tryCatchPattern":"if err := p.Start(handler); err != nil {\n    if strings.Contains(err.Error(), \"platform stopped\") {\n        p = max.New(opts)\n        err = p.Start(handler)\n    }\n}","preventionTips":["Never call Start after Stop on the same instance; create a new Platform","Serialize lifecycle transitions with a mutex or state machine","Await Stop completion before any restart logic"],"tags":["go","lifecycle","race-condition"],"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"}