{"record":{"id":"dc3fd06380766fd4","repo":"sipeed/picoclaw","slug":"wecom-qr-scan-succeeded-but-bot-credentials-are-mi","errorCode":null,"errorMessage":"WeCom QR scan succeeded but bot credentials are missing","messagePattern":"WeCom QR scan succeeded but bot credentials are missing","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"cmd/picoclaw/internal/auth/wecom.go","lineNumber":300,"sourceCode":"\n\ttimeoutCtx, cancel := context.WithTimeout(ctx, opts.PollTimeout)\n\tdefer cancel()\n\n\tvar scannedPrinted bool\n\n\tfor {\n\t\tstatus, err := queryWeComQRCodeStatus(timeoutCtx, opts, scode)\n\t\tif err != nil {\n\t\t\tif errors.Is(err, context.DeadlineExceeded) || errors.Is(timeoutCtx.Err(), context.DeadlineExceeded) {\n\t\t\t\treturn wecomQRBotInfo{}, fmt.Errorf(\"WeCom QR scan timed out after %s\", opts.PollTimeout)\n\t\t\t}\n\t\t\treturn wecomQRBotInfo{}, err\n\t\t}\n\n\t\tswitch strings.ToLower(status.Data.Status) {\n\t\tcase \"success\":\n\t\t\tif status.Data.BotInfo.BotID == \"\" || status.Data.BotInfo.Secret == \"\" {\n\t\t\t\treturn wecomQRBotInfo{}, fmt.Errorf(\"WeCom QR scan succeeded but bot credentials are missing\")\n\t\t\t}\n\t\t\treturn wecomQRBotInfo{\n\t\t\t\tBotID:  status.Data.BotInfo.BotID,\n\t\t\t\tSecret: status.Data.BotInfo.Secret,\n\t\t\t}, nil\n\t\tcase \"expired\":\n\t\t\treturn wecomQRBotInfo{}, fmt.Errorf(\"WeCom QR code expired, please retry\")\n\t\tcase \"scaned\", \"scanned\":\n\t\t\tif !scannedPrinted {\n\t\t\t\tfmt.Fprintln(opts.Writer, \"QR code scanned. Confirm the login in WeCom.\")\n\t\t\t\tscannedPrinted = true\n\t\t\t}\n\t\t}\n\n\t\tselect {\n\t\tcase <-timeoutCtx.Done():\n\t\t\tif errors.Is(timeoutCtx.Err(), context.DeadlineExceeded) {\n\t\t\t\treturn wecomQRBotInfo{}, fmt.Errorf(\"WeCom QR scan timed out after %s\", opts.PollTimeout)","sourceCodeStart":282,"sourceCodeEnd":318,"githubUrl":"https://github.com/sipeed/picoclaw/blob/49183d7e8daed0dba89ddbb6fcb60089401d9680/cmd/picoclaw/internal/auth/wecom.go#L282-L318","documentation":"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.","triggerScenarios":"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.","commonSituations":"Race on the relay side between confirmation and bot provisioning; API field rename between picoclaw and relay versions; partial outage producing hollow success responses.","solutions":["Retry the QR login — a fresh session usually gets a fully populated botInfo","Update picoclaw to pick up any response-schema fixes","If reproducible, capture the relay response (e.g. with a logging proxy) and report to maintainers","Check the relay service status for provisioning incidents"],"exampleFix":null,"handlingStrategy":"validation","validationCode":"// Validate before trusting a success payload\nif status.Data.BotInfo.BotID == \"\" || status.Data.BotInfo.Secret == \"\" {\n\t// treat as incomplete: re-generate QR instead of propagating bad creds\n}","typeGuard":"func hasBotCredentials(info wecomQRBotInfo) bool {\n\treturn strings.TrimSpace(info.BotID) != \"\" && strings.TrimSpace(info.Secret) != \"\"\n}","tryCatchPattern":null,"preventionTips":["Never persist or return bot credentials that fail the non-empty check","Retry the full QR flow on hollow success responses — usually a relay race"],"tags":["go","wecom","validation","api-contract"],"backgroundTag":null,"analyzedSha":"49183d7e8daed0dba89ddbb6fcb60089401d9680","analyzedAt":"2026-08-15T21:55:41.315Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}