{"record":{"id":"35324b5a260587d4","repo":"fish2018/pansou","slug":"s-d-w-35324b","errorCode":null,"errorMessage":"[%s] 重试 %d 次后仍失败: %w","messagePattern":"\\[(.+?)\\] 重试 (.+?) 次后仍失败: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"plugin/qiwei/qiwei.go","lineNumber":661,"sourceCode":"\tfor i := 0; i < maxRetries; i++ {\n\t\tif i > 0 {\n\t\t\ttime.Sleep(time.Duration(1<<uint(i-1)) * 200 * time.Millisecond)\n\t\t}\n\n\t\tresp, err := client.Do(req.Clone(req.Context()))\n\t\tif err == nil && resp != nil && resp.StatusCode == http.StatusOK {\n\t\t\treturn resp, nil\n\t\t}\n\t\tif resp != nil {\n\t\t\tresp.Body.Close()\n\t\t}\n\t\tlastErr = err\n\t}\n\n\tif lastErr == nil {\n\t\tlastErr = fmt.Errorf(\"unknown request error\")\n\t}\n\treturn nil, fmt.Errorf(\"[%s] 重试 %d 次后仍失败: %w\", p.Name(), maxRetries, lastErr)\n}\n\nfunc (p *QiweiPlugin) setHeaders(req *http.Request, referer string) {\n\treq.Header.Set(\"User-Agent\", userAgent)\n\treq.Header.Set(\"Accept\", \"text/html,application/xhtml+xml,application/xml;q=0.9,application/json;q=0.8,*/*;q=0.7\")\n\treq.Header.Set(\"Accept-Language\", \"zh-CN,zh;q=0.9,en;q=0.8\")\n\treq.Header.Set(\"Connection\", \"keep-alive\")\n\treq.Header.Set(\"Upgrade-Insecure-Requests\", \"1\")\n\tif referer != \"\" {\n\t\treq.Header.Set(\"Referer\", referer)\n\t}\n}\n\nfunc (p *QiweiPlugin) hostCandidates() []string {\n\tp.hostMu.RLock()\n\tactive := p.activeHost\n\tp.hostMu.RUnlock()\n","sourceCodeStart":643,"sourceCodeEnd":679,"githubUrl":"https://github.com/fish2018/pansou/blob/beaa56133755a548ebc51b090b3816e2ae044aa6/plugin/qiwei/qiwei.go#L643-L679","documentation":"doRequestWithRetry wraps the final failure as '[<plugin>] 重试 %d 次后仍失败: %w' after exhausting maxRetries=3 with exponential backoff (200ms, 400ms). It aggregates whatever error (transport error or the 'unknown request error' fallback) caused each attempt to fail. Any caller of solveVerification or fetchBody will see this error when the upstream qiwei server is unreachable or keeps rejecting the request.","triggerScenarios":"All 3 attempts of client.Do inside doRequestWithRetry fail — either with a transport error (DNS, timeout, TLS, connection refused) or a non-200 HTTP status; solveVerification/fetchBody then propagate this wrapped error.","commonSituations":"Corporate proxy/firewall blocking the host, DNS misconfiguration, TLS certificate problems (InsecureSkipVerify disabled upstream), the qiwei service being rate-limiting or down, or expired cookies causing repeated 4xx responses.","solutions":["Inspect the wrapped %w cause in the error message to identify the underlying failure (timeout vs refused vs status)","Verify network reachability: curl -v the qiwei URL from the host running the plugin","If timeouts, increase the http.Client Timeout used by the plugin","If repeated 4xx/5xx, refresh session cookies or wait for the upstream service to recover"],"exampleFix":"// before\nresp, err := p.doRequestWithRetry(req, client)\nif err != nil {\n    return err\n}\n// after\nresp, err := p.doRequestWithRetry(req, client)\nif err != nil {\n    var netErr net.Error\n    if errors.As(err, &netErr) && netErr.Timeout() {\n        return fmt.Errorf(\"qiwei request timed out, check network: %w\", err)\n    }\n    return err\n}","handlingStrategy":"retry","validationCode":"// verify reachability before heavy flows\nconn, err := net.DialTimeout(\"tcp\", \"open.weixin.qq.com:443\", 3*time.Second)\nif err != nil {\n    return fmt.Errorf(\"qiwei host unreachable: %w\", err)\n}\nconn.Close()","typeGuard":null,"tryCatchPattern":"resp, err := p.doRequestWithRetry(req, client)\nif err != nil {\n    var netErr net.Error\n    if errors.As(err, &netErr) && netErr.Timeout() {\n        return fmt.Errorf(\"qiwei upstream timeout after retries: %w\", err)\n    }\n    return fmt.Errorf(\"qiwei request failed: %w\", err)\n}","preventionTips":["Ensure stable outbound network/DNS on the deployment host","Configure proxy env vars (HTTP_PROXY/HTTPS_PROXY) if behind a corporate proxy","Honor the plugin's built-in 3-retry backoff; add circuit-breaking on repeated failures","Keep cookies/session state fresh to avoid repeated 4xx-driven retries"],"tags":["http","retry","network"],"backgroundTag":"http-request-failed","analyzedSha":"beaa56133755a548ebc51b090b3816e2ae044aa6","analyzedAt":"2026-09-07T00:31:18.025Z","contentChangedAt":"2026-09-07T00:31:18.025Z","schemaVersion":2},"datasetVersion":"2026-09-15T23:17:13.987Z"}