sipeed/picoclaw · warning
WeCom QR code expired, please retry
Error message
WeCom QR code expired, please retry
What it means
The QR session status polled as 'expired': the WeCom relay invalidated the QR code because it was not scanned-and-confirmed within its validity window. The session's scode is dead; polling cannot succeed and the flow aborts with a retry instruction.
Source
Thrown at cmd/picoclaw/internal/auth/wecom.go:307
status, err := queryWeComQRCodeStatus(timeoutCtx, opts, scode)
if err != nil {
if errors.Is(err, context.DeadlineExceeded) || errors.Is(timeoutCtx.Err(), context.DeadlineExceeded) {
return wecomQRBotInfo{}, fmt.Errorf("WeCom QR scan timed out after %s", opts.PollTimeout)
}
return wecomQRBotInfo{}, err
}
switch strings.ToLower(status.Data.Status) {
case "success":
if status.Data.BotInfo.BotID == "" || status.Data.BotInfo.Secret == "" {
return wecomQRBotInfo{}, fmt.Errorf("WeCom QR scan succeeded but bot credentials are missing")
}
return wecomQRBotInfo{
BotID: status.Data.BotInfo.BotID,
Secret: status.Data.BotInfo.Secret,
}, nil
case "expired":
return wecomQRBotInfo{}, fmt.Errorf("WeCom QR code expired, please retry")
case "scaned", "scanned":
if !scannedPrinted {
fmt.Fprintln(opts.Writer, "QR code scanned. Confirm the login in WeCom.")
scannedPrinted = true
}
}
select {
case <-timeoutCtx.Done():
if errors.Is(timeoutCtx.Err(), context.DeadlineExceeded) {
return wecomQRBotInfo{}, fmt.Errorf("WeCom QR scan timed out after %s", opts.PollTimeout)
}
return wecomQRBotInfo{}, timeoutCtx.Err()
case <-time.After(opts.PollInterval):
}
}
}
View on GitHub (pinned to 49183d7e8d)
Solutions
- Re-run the WeCom login command to get a fresh QR code and scan immediately
- Avoid starting multiple simultaneous login sessions (a new code can invalidate the old one)
- Use the printed QR Code Link URL directly if camera scanning is slow
- Confirm the login promptly in the WeCom app after scanning
Defensive patterns
Strategy: retry
Type guard
func isQRExpired(err error) bool {
return err != nil && strings.Contains(err.Error(), "QR code expired")
} Try / catch
info, err := pollWeComQRCodeResult(ctx, opts, session.SCode)
if isQRExpired(err) {
// automatically fetch a fresh QR and restart polling (bounded retries)
} Prevention
- Scan immediately after the QR renders; do not reuse terminal scrollback QRs
- Run only one login session at a time — new codes invalidate old ones
When it happens
Trigger: User requested a QR code but scanned it too late; user scanned but never confirmed in the WeCom app within the validity window; relay expired the code server-side due to a newer code being issued for the same source.
Common situations: User starts login, gets distracted, then scans minutes later; generating a QR in a second terminal invalidates the first; slow phone camera making the user miss the window.
Related errors
- failed to load config: %w
- failed to save config: %w
- failed to get WeCom QR code: %w
- failed to get WeCom QR code: errcode=%d errmsg=%s
- failed to get WeCom QR code: response missing scode or auth_
AI-assisted analysis of sipeed/picoclaw@49183d7e8d (2026-08-15).
Data as JSON: /api/errors/3ffaf1c6f5acc2f9.
Report an issue: GitHub.