{"record":{"id":"97a05e50f68ea4fb","repo":"chenhg5/cc-connect","slug":"cloud-web-platform-stopped","errorCode":null,"errorMessage":"cloud_web: platform stopped","messagePattern":"cloud_web: platform stopped","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"platform/cloud-web/cloudweb.go","lineNumber":171,"sourceCode":"\t}\n\treturn 0\n}\n\nfunc (p *Platform) Name() string { return p.name }\n\nfunc (p *Platform) SetLifecycleHandler(h core.PlatformLifecycleHandler) {\n\tp.lifecycleHandler = h\n}\n\nfunc (p *Platform) SetCardNavigationHandler(h core.CardNavigationHandler) {\n\tp.navHandler = h\n}\n\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(\"cloud_web: 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\tif ws, ok := p.tp.(*wsTransport); ok {\n\t\tws.onConnected = p.notifyReady\n\t\tws.onDisconnected = p.notifyUnavailable\n\t}\n\n\tif err := p.tp.Start(ctx, p.handleWire); err != nil {\n\t\tcancel()\n\t\treturn err\n\t}\n\n\t// WebSocket connects asynchronously; readiness is signaled after register_ack.\n\tif _, isWS := p.tp.(*wsTransport); !isWS {","sourceCodeStart":153,"sourceCodeEnd":189,"githubUrl":"https://github.com/chenhg5/cc-connect/blob/4000b2338aa6e850c99df54f8b0ed6ed7460b401/platform/cloud-web/cloudweb.go#L153-L189","documentation":"Platform.Start refuses to run when the platform is already stopping (Stop was called or is in progress). Starting a message handler on a shutting-down platform is rejected to avoid racing teardown: it would create a new context whose cancellation ownership conflicts with Stop.","triggerScenarios":"Calling p.Start(handler) after p.Stop() has been invoked, or concurrently while another goroutine is inside Stop (stopping flag set under p.mu).","commonSituations":"Engine restart/reconnect logic that recreates the handler without recreating the Platform; a graceful-shutdown path that races with an auto-reconnect loop; tests reusing a platform instance across subtests after teardown.","solutions":["Create a new Platform instance via New after Stop; Platform is single-use across start/stop cycles","Guard the start/stop sequence so Stop cannot run while Start is pending (serialize with your own mutex or lifecycle state machine)","Check logs for a concurrent Stop call (engine shutdown) and delay/retry Start after full shutdown completes, using a fresh instance"],"exampleFix":"// before\np.Stop()\nerr := p.Start(handler) // error: platform stopped\n\n// after\np.Stop()\np, err := cloudweb.New(cfg...)\nif err != nil { return err }\nerr = p.Start(handler)","handlingStrategy":"try-catch","validationCode":"// track lifecycle yourself\nif p.IsStopped() {\n    p, err = cloudweb.New(cfg...) // recreate before starting\n}","typeGuard":null,"tryCatchPattern":"if err := p.Start(handler); err != nil {\n    if strings.Contains(err.Error(), \"platform stopped\") {\n        p, err = cloudweb.New(cfg...)\n        if err == nil { err = p.Start(handler) }\n    }\n    return err\n}","preventionTips":["Treat Platform as single-use: one Start per instance","Serialize Start/Stop through a single supervisor goroutine","Recreate the platform on reconnect instead of restarting the old instance"],"tags":["lifecycle","concurrency","cloud-web"],"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-14T00:17:10.932Z"}