sipeed/picoclaw · info
channel stopped during QR setup
Error message
channel stopped during QR setup
What it means
Returned by WhatsAppNativeChannel.Start when the stopping flag is observed while holding reconnectMu during QR-login setup - i.e. Stop() ran concurrently with Start(). This is a deliberate clean abort, not a fault: the just-connected client is disconnected by the deferred cleanup and Start reports that the channel never came up. Note it is a plain error with no %w sentinel.
Source
Thrown at pkg/channels/whatsapp_native/whatsapp_native.go:176
if client.Store.ID == nil {
qrChan, err := client.GetQRChannel(c.runCtx)
if err != nil {
return fmt.Errorf("get QR channel: %w", err)
}
if err := client.Connect(); err != nil {
return fmt.Errorf("connect: %w", err)
}
// Handle QR events in a background goroutine so Start() returns
// promptly. The goroutine is tracked via c.wg and respects
// c.runCtx for cancellation.
// Guard wg.Add with reconnectMu + stopping check (same protocol
// as eventHandler) so a concurrent Stop() cannot enter wg.Wait()
// while we call wg.Add(1).
c.reconnectMu.Lock()
if c.stopping.Load() {
c.reconnectMu.Unlock()
return fmt.Errorf("channel stopped during QR setup")
}
c.wg.Add(1)
c.reconnectMu.Unlock()
go func() {
defer c.wg.Done()
for {
select {
case <-c.runCtx.Done():
return
case evt, ok := <-qrChan:
if !ok {
return
}
if evt.Event == "code" {
logger.InfoCF("whatsapp", "Scan this QR code with WhatsApp (Linked Devices):", nil)
qrterminal.GenerateWithConfig(evt.Code, qrterminal.Config{
Level: qrterminal.L,
Writer: os.Stdout,View on GitHub (pinned to 49183d7e8d)
Solutions
- No repair needed - this is graceful cancellation; simply Start again after Stop completes.
- In supervision code, wait for Stop() to return before issuing the next Start().
- Treat this message as informational in log alerting rather than an incident.
Defensive patterns
Strategy: validation
Validate before calling
// Ensure Stop has fully returned (it waits on c.wg) before starting again:
if err := ch.Stop(stopCtx); err != nil { return err }
// only then:
return ch.Start(ctx) Try / catch
if err := ch.Start(ctx); err != nil {
if errors.Is(err, context.Canceled) || strings.Contains(err.Error(), "stopped during QR setup") {
// benign abort: retry Start after lifecycle settles
}
} Prevention
- Treat this message as a no-op in alerting.
- Serialize Stop->Start sequences in reconfiguration code.
- Prefer the manager's restart APIs over manual Stop/Start pairs.
When it happens
Trigger: Stop(ctx) is called between client.Connect() and the wg.Add(1) for the QR goroutine; the stopping.Store(true) from Stop becomes visible under the reconnectMu lock and Start bails out.
Common situations: Rapid restart cycles (supervisor stop+start), config reloads that stop channels mid-start, or shutdown initiated while an unpaired channel is printing QR codes.
Related errors
AI-assisted analysis of sipeed/picoclaw@49183d7e8d (2026-08-15).
Data as JSON: /api/errors/8cbb3e0456ffd9da.
Report an issue: GitHub.