chenhg5/cc-connect · error
discord: platform stopped
Error message
discord: platform stopped
What it means
Platform.Start checks a p.stopping flag under mutex; if a Stop() was already issued, Start refuses to boot the bot and returns "discord: platform stopped". This guard exists so a platform that was permanently stopped (or is shutting down) is never resurrected with a stale handler — a fix for a past release-gate bug where Discord stayed offline until manual restart.
Source
Thrown at platform/discord/discord.go:550
func (p *Platform) SetLifecycleHandler(h core.PlatformLifecycleHandler) {
p.mu.Lock()
defer p.mu.Unlock()
p.lifecycleHandler = h
}
// Start launches the gateway connection in the background. It returns nil as
// soon as the recovery loop is running; the caller should treat
// OnPlatformReady as the signal that the platform is actually usable.
//
// Before this change Start returned the first session.Open() error directly,
// which meant a transient proxy/network blip during cc-connect startup
// permanently took Discord offline until manual restart (release-gate
// 2026-06-14: "discord: open gateway: ... EOF" with no retry).
func (p *Platform) Start(handler core.MessageHandler) error {
p.mu.Lock()
if p.stopping {
p.mu.Unlock()
return fmt.Errorf("discord: platform stopped")
}
p.handler = handler
ctx, cancel := context.WithCancel(context.Background())
p.cancel = cancel
p.mu.Unlock()
go p.connectLoop(ctx)
return nil
}
// buildSession creates a fresh discordgo session with proxy + handlers wired up.
// It is called once per connect attempt so a session that failed mid-handshake
// is fully discarded before the next retry.
func (p *Platform) buildSession() (*discordgo.Session, error) {
session, err := discordgo.New("Bot " + p.token)
if err != nil {
return nil, fmt.Errorf("discord: create session: %w", err)
}View on GitHub (pinned to 4000b2338a)
Solutions
- Construct a fresh Platform instance (NewPlatform with config) instead of calling Start on a previously stopped one.
- Audit the lifecycle: never call Start concurrently with or after Stop; use a restart method that resets the stopping flag if restarts are intended.
- Serialize lifecycle calls with a mutex/sync.Once in the caller (daemon/supervisor layer).
- If restart support is needed, add an explicit Reset/restart API rather than flipping p.stopping back.
Example fix
// before p.Stop() err := p.Start(handler) // error: discord: platform stopped // after p.Stop() p = discord.NewPlatform(cfg) // fresh instance err := p.Start(handler)
Defensive patterns
Strategy: type-guard
Validate before calling
p.mu.Lock()
stopping := p.stopping
p.mu.Unlock()
if stopping {
p = discord.NewPlatform(cfg) // rebuild instead of restarting
} Type guard
func isStopped(p *Platform) bool { p.mu.Lock(); defer p.mu.Unlock(); return p.stopping } Try / catch
if err := p.Start(handler); err != nil {
if strings.Contains(err.Error(), "platform stopped") {
p = discord.NewPlatform(cfg)
return p.Start(handler)
}
return err
} Prevention
- Treat Platform as single-use: one Start, one Stop.
- Serialize lifecycle transitions in the daemon layer to avoid stop/start races.
- For restarts, build a new instance from config rather than reusing the stopped one.
When it happens
Trigger: Calling Start after Stop() on the same Platform instance, a lifecycle race where the daemon's shutdown path ran before (or concurrently with) a restart attempt, or reusing a stopped Platform object instead of constructing a new one.
Common situations: Config-reload/restart logic calling Stop then Start on the same instance where Stop set stopping=true permanently, tests reusing a stopped platform, shutdown signal handlers racing with reconnection logic.
Understand the failure class
Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.
Related errors
- codex app-server connection is closed
- session is closed
- session is closed
- tmux: session closed
- tmux: session %q does not exist and auto_create is disabled
AI-assisted analysis of chenhg5/cc-connect@4000b2338a (2026-09-06).
Data as JSON: /api/errors/da01f4810e6944e1.
Report an issue: GitHub.