{"record":{"id":"706ad698d47ec7df","repo":"chenhg5/cc-connect","slug":"login-confirmed-but-bot-token-missing","errorCode":null,"errorMessage":"login confirmed but bot_token missing","messagePattern":"login confirmed but bot_token missing","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"cmd/cc-connect/weixin.go","lineNumber":368,"sourceCode":"\t\t\t\tfmt.Printf(\"URL: %s\\n\\n\", newURL)\n\t\t\t\ttryPrintTerminalQRCode(newURL)\n\t\t\t}\n\t\t\t// 过期刷新时同步更新 QR 图片文件\n\t\t\tif opts.QRImage != \"\" {\n\t\t\t\tif err := saveQRCodeImage(newURL, opts.QRImage); err != nil {\n\t\t\t\t\tfmt.Fprintf(os.Stderr, \"Warning: failed to update QR image: %v\\n\", err)\n\t\t\t\t} else {\n\t\t\t\t\tfmt.Printf(\"QR code updated at: %s\\n\\n\", opts.QRImage)\n\t\t\t\t}\n\t\t\t}\n\t\t\ttime.Sleep(time.Second)\n\t\t\tcontinue\n\t\tcase \"confirmed\":\n\t\t\tif strings.TrimSpace(status.IlinkBotID) == \"\" {\n\t\t\t\treturn nil, fmt.Errorf(\"login confirmed but ilink_bot_id missing\")\n\t\t\t}\n\t\t\tif strings.TrimSpace(status.BotToken) == \"\" {\n\t\t\t\treturn nil, fmt.Errorf(\"login confirmed but bot_token missing\")\n\t\t\t}\n\t\t\tfmt.Println(\"\\n✅ 已与微信建立连接。\")\n\t\t\treturn &weixinQRLoginResult{\n\t\t\t\tBotToken:    strings.TrimSpace(status.BotToken),\n\t\t\t\tIlinkBotID:  strings.TrimSpace(status.IlinkBotID),\n\t\t\t\tBaseURL:     strings.TrimSpace(status.BaseURL),\n\t\t\t\tIlinkUserID: strings.TrimSpace(status.IlinkUserID),\n\t\t\t}, nil\n\t\tdefault:\n\t\t\ttime.Sleep(time.Second)\n\t\t}\n\t}\n\n\treturn nil, fmt.Errorf(\"等待扫码超时，请重试\")\n}\n\nfunc weixinHTTPGet(ctx context.Context, fullURL, routeTag string, debug bool) ([]byte, error) {\n\treq, err := http.NewRequestWithContext(ctx, http.MethodGet, fullURL, nil)","sourceCodeStart":350,"sourceCodeEnd":386,"githubUrl":"https://github.com/chenhg5/cc-connect/blob/4000b2338aa6e850c99df54f8b0ed6ed7460b401/cmd/cc-connect/weixin.go#L350-L386","documentation":"Immediately after the ilink_bot_id check, the \"confirmed\" branch validates status.BotToken. A confirmed login without a bot_token cannot authenticate future API calls, so runWeixinQRLoginFlow fails with \"login confirmed but bot_token missing\". Like the ilink_bot_id error, this points to an incomplete server response rather than user error.","triggerScenarios":"`cc-connect weixin setup` QR flow: poll status becomes \"confirmed\", IlinkBotID is present, but strings.TrimSpace(status.BotToken) == \"\" in the status payload.","commonSituations":"ilink server bug or partial rollout withholding the token; API field renamed (e.g. bot_token → token) after a server upgrade; token issuance disabled or failing server-side for the account; stub API used for testing.","solutions":["Retry `cc-connect weixin setup`; token issuance failures are often transient.","Inspect the confirmed status payload in debug output to confirm the field name/shape hasn't changed.","Verify APIBaseURL points at the correct, current ilink API endpoint.","Check the account's bot status on the ilink platform — token issuance may be blocked for it.","Use `cc-connect weixin bind --token ...` with a token obtained directly from the console as a workaround."],"exampleFix":"// before\nif strings.TrimSpace(status.BotToken) == \"\" {\n    return nil, fmt.Errorf(\"login confirmed but bot_token missing\")\n}\n\n// after: also accept alternate field name from newer API versions\ntok := strings.TrimSpace(status.BotToken)\nif tok == \"\" { tok = strings.TrimSpace(status.Token) }\nif tok == \"\" {\n    return nil, fmt.Errorf(\"login confirmed but bot_token missing\")\n}","handlingStrategy":"type-guard","validationCode":"// Validate the confirmed status carries a token before consuming:\nif status.Status == \"confirmed\" && strings.TrimSpace(status.BotToken) == \"\" {\n    slog.Warn(\"server returned confirmed without bot_token; retrying\")\n}","typeGuard":"func hasBotToken(s *pollStatus) bool {\n    return s != nil && strings.TrimSpace(s.BotToken) != \"\"\n}","tryCatchPattern":"res, err := runWeixinQRLoginFlow(ctx, opts)\nif err != nil && strings.Contains(err.Error(), \"bot_token missing\") {\n    // incomplete server payload; retry setup or bind with a manual token\n    return fmt.Errorf(\"no token returned; rerun setup or use bind --token\")\n}","preventionTips":["Never persist credentials from a confirmed status without a non-empty bot_token","Track ilink API changes to the token field name","Verify account-level token issuance is enabled before setup","Keep bind --token as an escape hatch documented for users"],"tags":["weixin","token","missing-field"],"backgroundTag":"unexpected-api-response-shape","analyzedSha":"4000b2338aa6e850c99df54f8b0ed6ed7460b401","analyzedAt":"2026-09-06T11:45:09.575Z","contentChangedAt":"2026-09-06T11:45:09.575Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}