sipeed/picoclaw · error

WeCom QR scan succeeded but bot credentials are missing

Error message

WeCom QR scan succeeded but bot credentials are missing

What it means

The relay reported scan status 'success' but the botInfo payload inside it was incomplete: BotID or Secret was an empty string. The code refuses to return credentials that would later fail channel startup — a defensive check against a truncated/malformed success response.

Source

Thrown at cmd/picoclaw/internal/auth/wecom.go:300

	timeoutCtx, cancel := context.WithTimeout(ctx, opts.PollTimeout)
	defer cancel()

	var scannedPrinted bool

	for {
		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)

View on GitHub (pinned to 49183d7e8d)

Solutions

  1. Retry the QR login — a fresh session usually gets a fully populated botInfo
  2. Update picoclaw to pick up any response-schema fixes
  3. If reproducible, capture the relay response (e.g. with a logging proxy) and report to maintainers
  4. Check the relay service status for provisioning incidents
Defensive patterns

Strategy: validation

Validate before calling

// Validate before trusting a success payload
if status.Data.BotInfo.BotID == "" || status.Data.BotInfo.Secret == "" {
	// treat as incomplete: re-generate QR instead of propagating bad creds
}

Type guard

func hasBotCredentials(info wecomQRBotInfo) bool {
	return strings.TrimSpace(info.BotID) != "" && strings.TrimSpace(info.Secret) != ""
}

Prevention

When it happens

Trigger: Relay marks the scan successful before the bot is fully provisioned, returning empty bot fields; relay response schema change renames bot_id/secret so they decode as empty strings; relay bug during high load.

Common situations: Race on the relay side between confirmation and bot provisioning; API field rename between picoclaw and relay versions; partial outage producing hollow success responses.

Related errors


AI-assisted analysis of sipeed/picoclaw@49183d7e8d (2026-08-15). Data as JSON: /api/errors/dc3fd06380766fd4. Report an issue: GitHub.