{"record":{"id":"2459b54cf8755ad9","repo":"chenhg5/cc-connect","slug":"get-bot-qrcode-json-w","errorCode":null,"errorMessage":"get_bot_qrcode json: %w","messagePattern":"get_bot_qrcode json: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"cmd/cc-connect/weixin.go","lineNumber":440,"sourceCode":"}\n\nfunc weixinFetchBotQRCode(ctx context.Context, apiBase, botType, routeTag string, debug bool) (*weixinBotQRResponse, error) {\n\tbase := strings.TrimRight(apiBase, \"/\") + \"/\"\n\tu, err := url.Parse(base)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tu = u.JoinPath(\"ilink\", \"bot\", \"get_bot_qrcode\")\n\tq := u.Query()\n\tq.Set(\"bot_type\", botType)\n\tu.RawQuery = q.Encode()\n\traw, err := weixinHTTPGet(ctx, u.String(), routeTag, debug)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"get_bot_qrcode: %w\", err)\n\t}\n\tvar out weixinBotQRResponse\n\tif err := json.Unmarshal(raw, &out); err != nil {\n\t\treturn nil, fmt.Errorf(\"get_bot_qrcode json: %w\", err)\n\t}\n\treturn &out, nil\n}\n\nfunc weixinPollQRStatus(ctx context.Context, apiBase, qrKey, routeTag string, debug bool) (*weixinQRStatusResponse, error) {\n\tbase := strings.TrimRight(apiBase, \"/\") + \"/\"\n\tu, err := url.Parse(base)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tu = u.JoinPath(\"ilink\", \"bot\", \"get_qrcode_status\")\n\tq := u.Query()\n\tq.Set(\"qrcode\", qrKey)\n\tu.RawQuery = q.Encode()\n\n\tpollCtx, cancel := context.WithTimeout(ctx, weixinQRPollTimeout+2*time.Second)\n\tdefer cancel()\n","sourceCodeStart":422,"sourceCodeEnd":458,"githubUrl":"https://github.com/chenhg5/cc-connect/blob/4000b2338aa6e850c99df54f8b0ed6ed7460b401/cmd/cc-connect/weixin.go#L422-L458","documentation":"After a successful HTTP 200 from `get_bot_qrcode`, weixinFetchBotQRCode decodes the response body into weixinBotQRResponse with json.Unmarshal. If the body is not valid JSON (or has the wrong types), this error wraps the unmarshal failure. It means the server replied but not with the expected JSON document.","triggerScenarios":"GET to `ilink/bot/get_bot_qrcode` returns 200 with an HTML error page, empty body, or JSON whose fields do not match weixinBotQRResponse's types (e.g. a string where a number is expected).","commonSituations":"A transparent proxy or captive portal intercepting the request and returning HTML; API version change altering the response schema; wrong endpoint path returning a 200 text page.","solutions":["Log/dump the raw response body to see what was actually returned","Check for proxy/captive-portal interference returning HTML with status 200","Compare the response shape against weixinBotQRResponse and update the struct if the API schema changed","Verify the endpoint URL is the real ilink API and not a redirect target"],"exampleFix":null,"handlingStrategy":"type-guard","validationCode":"if !json.Valid(raw) {\n    return fmt.Errorf(\"get_bot_qrcode: non-JSON response: %.100s\", raw)\n}","typeGuard":"func looksLikeBotQR(raw []byte) bool {\n    var probe struct { QRKey string `json:\"qr_key\"` }\n    return json.Unmarshal(raw, &probe) == nil && probe.QRKey != \"\"\n}","tryCatchPattern":"raw, err := weixinHTTPGet(ctx, u, routeTag, debug)\nif err != nil { return err }\nif !looksLikeBotQR(raw) {\n    return fmt.Errorf(\"get_bot_qrcode: unexpected payload: %.200s\", raw)\n}","preventionTips":["Bypass proxies/captive portals for API hosts","Log raw bodies on parse failure to spot schema drift","Pin and review the ilink API version you target","Validate response shapes in CI against a fixture"],"tags":["json","unmarshal","weixin","qr-login"],"backgroundTag":"json-unmarshal-failed","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"}