fish2018/pansou · error

读取二维码失败

Error message

读取二维码失败: %w

What it means

After a successful 200 response, generateQRCodeWithSig reads the QR-code image body with ioutil.ReadAll; if the read fails (connection reset mid-body, timeout, truncated response), it wraps the io error as "读取二维码失败". The QR image bytes cannot be obtained, so login state rendering must abort.

Solutions

  1. Retry the QR-code request; transient body-read errors usually succeed on a second attempt.
  2. Increase the HTTP client timeout (http.Client{Timeout: ...}) if large latencies cause the read to expire.
  3. Check proxy/firewall stability if behind a corporate or residential proxy.
  4. Check the wrapped %w error for the root cause (reset, EOF, timeout) and address that specifically.

Example fix

// before
client := &http.Client{} // no timeout
// after
client := &http.Client{Timeout: 15 * time.Second}
...
qrcodeBytes, err := io.ReadAll(resp.Body)
if err != nil {
    return nil, "", fmt.Errorf("读取二维码失败: %w", err) // retry caller-side
}
Defensive patterns

Strategy: retry

Try / catch

qrcodeBytes, _, err := generateQRCodeWithSig(...)
if err != nil {
    var netErr net.Error
    if errors.As(err, &netErr) && netErr.Timeout() {
        // increase timeout and retry once
    }
}

Prevention

When it happens

Trigger: ioutil.ReadAll(resp.Body) returns an error after the QR endpoint returned 200 — e.g. connection reset by peer, context deadline exceeded, or proxy dropping the stream mid-transfer.

Common situations: Unstable network or proxy between client and the QQ QR endpoint; server closes connection early under load; HTTP client timeout shorter than the image transfer needs.

Understand the failure class

Background: "failed to read file", EACCES, ENOENT and "could not read <path>" errors: when a program can't read a file from disk — this error's family across 49 libraries.

Related errors


AI-assisted analysis of fish2018/pansou@beaa561337 (2026-09-07). Data as JSON: /api/errors/1efcfeed8fd722ad. Report an issue: GitHub.

Appendix: source

Thrown at plugin/qqpd/qqpd.go:2092

		Transport: &http.Transport{
			TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
		},
	}

	resp, err := client.Get(qrcodeURL)
	if err != nil {
		return nil, "", fmt.Errorf("请求二维码失败: %w", err)
	}
	defer resp.Body.Close()

	if resp.StatusCode != 200 {
		return nil, "", fmt.Errorf("二维码请求返回状态码: %d", resp.StatusCode)
	}

	// 读取二维码图片
	qrcodeBytes, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return nil, "", fmt.Errorf("读取二维码失败: %w", err)
	}

	// 提取qrsig(用于后续登录检测)
	setCookie := resp.Header.Get("Set-Cookie")
	qrsig := extractQrsig(setCookie)
	if qrsig != "" && DebugLog {
		fmt.Printf("[QQPD] 二维码生成成功,qrsig: %s\n", qrsig[:20]+"...")
	}

	return qrcodeBytes, qrsig, nil
}

// extractQrsig 从Set-Cookie中提取qrsig
func extractQrsig(setCookie string) string {
	cookies := strings.Split(setCookie, ";")
	for _, cookie := range cookies {
		cookie = strings.TrimSpace(cookie)
		if strings.HasPrefix(cookie, "qrsig=") {

View on GitHub (pinned to beaa561337)