{"record":{"id":"27d6ac0ffdc67fc8","repo":"chenhg5/cc-connect","slug":"weixin-platform-stopped","errorCode":null,"errorMessage":"weixin: platform stopped","messagePattern":"weixin: platform stopped","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"platform/weixin/weixin.go","lineNumber":417,"sourceCode":"\t}\n\treturn true\n}\n\nfunc (p *Platform) pauseSession(d time.Duration) {\n\tif d <= 0 {\n\t\td = time.Hour\n\t}\n\tp.pauseMu.Lock()\n\tp.pauseUntil = time.Now().Add(d)\n\tp.pauseMu.Unlock()\n\tslog.Warn(\"weixin: session paused after gateway error\", \"duration\", d, \"account\", p.accountLabel)\n}\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(\"weixin: platform stopped\")\n\t}\n\tp.handler = handler\n\tctx, cancel := context.WithCancel(context.Background())\n\tp.cancel = cancel\n\tgo p.pollLoop(ctx)\n\treturn nil\n}\n\n// SetLifecycleHandler registers a handler that will be notified once the ilink\n// long-poll has confirmed a working session. Implements\n// core.AsyncRecoverablePlatform so the engine waits for the actual\n// ready-for-poll signal before logging \"platform ready\" and initialising\n// platform-level capabilities.\nfunc (p *Platform) SetLifecycleHandler(h core.PlatformLifecycleHandler) {\n\tp.mu.Lock()\n\tdefer p.mu.Unlock()\n\tp.lifecycleHandler = h\n}","sourceCodeStart":399,"sourceCodeEnd":435,"githubUrl":"https://github.com/chenhg5/cc-connect/blob/4000b2338aa6e850c99df54f8b0ed6ed7460b401/platform/weixin/weixin.go#L399-L435","documentation":"Start registers the message handler and launches the long-poll loop. If the platform has already been asked to stop (p.stopping is set by Stop), Start refuses to run and returns this sentinel error instead of spawning a new poll loop.","triggerScenarios":"Calling Start(handler) after Stop() was called on the same Platform instance, or racing Start against a concurrent Stop that flips p.stopping first.","commonSituations":"Restart logic that reuses the old platform object instead of constructing a new one via New(); engine shutdown calls Stop then a late reconnect attempts Start on the same instance; tests tearing down and restarting without rebuilding the platform.","solutions":["Create a fresh Platform via weixin.New() instead of re-Starting a stopped one","Reorder logic so Start is never called after Stop on the same instance","Guard restarts with the error and rebuild/reconfigure before retrying"],"exampleFix":"// before\np.Stop()\np.Start(handler) // fails: platform stopped\n// after\np.Stop()\np, err := weixin.New(opts)\nif err != nil { return err }\nreturn p.Start(handler)","handlingStrategy":"type-guard","validationCode":"// track lifecycle before calling\nif platformAlreadyStopped {\n    return errors.New(\"recreate platform instead of restarting\")\n}","typeGuard":null,"tryCatchPattern":"if err := p.Start(handler); err != nil && err.Error() == \"weixin: platform stopped\" {\n    np, nerr := weixin.New(opts)\n    if nerr != nil { return nerr }\n    return np.Start(handler)\n}","preventionTips":["Treat Platform instances as single-use across Start/Stop cycles","Synchronize shutdown/restart paths to avoid Start/Stop races","Build a fresh platform via New for every reconnect"],"tags":["go","lifecycle","weixin","concurrency"],"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"}