{"record":{"id":"d4547206618f909a","repo":"chenhg5/cc-connect","slug":"tuitui-platform-stopped","errorCode":null,"errorMessage":"tuitui: platform stopped","messagePattern":"tuitui: platform stopped","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"platform/tuitui/tuitui.go","lineNumber":173,"sourceCode":"\t\tallowFrom:             allowFrom,\n\t\tgroupAllowFrom:        groupAllowFrom,\n\t\tignoreFrom:            ignoreFrom,\n\t\tgroupPolicy:           groupPolicy,\n\t\treceiveReaction:       receiveReaction,\n\t\trequireMention:        requireMention,\n\t\tshareSessionInChannel: shareSessionInChannel,\n\t\tpendingHistoryLimit:   pendingHistoryLimit,\n\t\tclient:                &http.Client{Timeout: httpTimeout},\n\t}, nil\n}\n\nfunc (p *Platform) Name() string { return \"tuitui\" }\n\nfunc (p *Platform) Start(handler core.MessageHandler) error {\n\tp.mu.Lock()\n\tdefer p.mu.Unlock()\n\tif p.stopping {\n\t\treturn fmt.Errorf(\"tuitui: platform stopped\")\n\t}\n\tp.handler = handler\n\tctx, cancel := context.WithCancel(context.Background())\n\tp.cancel = cancel\n\tgo p.connectLoop(ctx)\n\treturn nil\n}\n\nfunc (p *Platform) Stop() error {\n\tp.mu.Lock()\n\tdefer p.mu.Unlock()\n\tp.stopping = true\n\tif p.cancel != nil {\n\t\tp.cancel()\n\t}\n\treturn nil\n}\n","sourceCodeStart":155,"sourceCodeEnd":191,"githubUrl":"https://github.com/chenhg5/cc-connect/blob/4000b2338aa6e850c99df54f8b0ed6ed7460b401/platform/tuitui/tuitui.go#L155-L191","documentation":"Start() refuses to (re)start the platform once p.stopping has been set, i.e. after Stop() was called or shutdown began. It also registers the message handler and launches the connect loop only on a successful start. This guards against reusing a Platform instance that is being torn down.","triggerScenarios":"Calling Start(handler) on a *Platform whose Stop() was already invoked, or calling Start concurrently with shutdown; typically a restart attempt on the same instance after engine teardown.","commonSituations":"Config reload code that stops then tries to Start the same Platform object instead of constructing a new one; a reconnect loop at the application level calling Start after a graceful shutdown; race between Stop and Start during app exit.","solutions":["Create a fresh Platform instance via tuitui.New and Start that instead of restarting the stopped one.","Ensure Stop() is only called at final teardown; order your lifecycle so Start always precedes Stop.","Synchronize Start/Stop calls (mutex or single lifecycle owner) to avoid racing with stopping."],"exampleFix":"// before\np.Stop()\nerr := p.Start(handler) // fails: platform stopped\n// after\np.Stop()\np2, err := tuitui.New(opts)\nif err == nil {\n    err = p2.Start(handler)\n}","handlingStrategy":"fallback","validationCode":"// track lifecycle at call site\nif platformStopped {\n    p, err = tuitui.New(opts)\n}","typeGuard":"func (p *tuitui.Platform) isStopped() bool { return p.Stopped() } // if exposed","tryCatchPattern":"if err := p.Start(handler); err != nil && strings.Contains(err.Error(), \"platform stopped\") {\n    p = mustNewPlatform(opts)\n    err = p.Start(handler)\n}","preventionTips":["Treat Platform objects as single-use: new instance per start.","Centralize lifecycle management in one owner goroutine.","Never call Start after Stop; rebuild instead."],"tags":["lifecycle","platform","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"}