{"record":{"id":"32ae0c9ac1438b37","repo":"fish2018/pansou","slug":"unknown-request-error","errorCode":null,"errorMessage":"unknown request error","messagePattern":"unknown request error","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"plugin/qiwei/qiwei.go","lineNumber":659,"sourceCode":"\tvar lastErr error\n\n\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","sourceCodeStart":641,"sourceCodeEnd":677,"githubUrl":"https://github.com/fish2018/pansou/blob/beaa56133755a548ebc51b090b3816e2ae044aa6/plugin/qiwei/qiwei.go#L641-L677","documentation":"This is a fallback sentinel inside QiweiPlugin.doRequestWithRetry (plugin/qiwei/qiwei.go:659). After 3 attempts the loop reports the last transport/status error; if lastErr is somehow nil (e.g. the server consistently returned a non-200 status so no err was recorded), this 'unknown request error' is used as the wrapped cause. It signals the request failed for a non-obvious reason — most often repeated non-200 HTTP responses.","triggerScenarios":"solveVerification or fetchBody calls doRequestWithRetry; all 3 attempts get an HTTP response with StatusCode != 200, so client.Do returns no error and lastErr stays nil when the fallback is built.","commonSituations":"WeCom (qiwei) endpoint temporarily returning 4xx/5xx (rate limiting, maintenance, blocked UA), a proxy/gateway returning 502/503 repeatedly, or the target page redirecting to an anti-bot challenge page with a non-200 code.","solutions":["Log resp.StatusCode on each retry attempt to see which non-200 status is actually occurring","Check network/proxy connectivity to the qiwei endpoint (curl -v the URL)","Retry later with backoff — the plugin already retries 3 times with exponential backoff, so persistent failure means the endpoint is down or blocking","If caused by anti-bot blocking, refresh cookies/verification state before calling again"],"exampleFix":"// before\nif lastErr == nil {\n    lastErr = fmt.Errorf(\"unknown request error\")\n}\n// after\nif lastErr == nil {\n    lastErr = fmt.Errorf(\"non-200 status after retries\")\n}","handlingStrategy":"retry","validationCode":"// caller-side: prefer checking status explicitly if you control the client\nreq, _ := http.NewRequestWithContext(ctx, \"GET\", qiweiURL, nil)\nif req == nil || qiweiURL == \"\" {\n    return errors.New(\"qiwei request not initialized\")\n}","typeGuard":"if resp != nil && resp.StatusCode == http.StatusOK {\n    // safe to use resp\n}","tryCatchPattern":"resp, err := p.doRequestWithRetry(req, client)\nif err != nil {\n    if strings.Contains(err.Error(), \"unknown request error\") {\n        // non-200 after all retries; inspect upstream status/health\n    }\n    return err\n}","preventionTips":["Monitor the qiwei endpoint's health/status codes","Refresh session cookies before long-running request loops","Set realistic client timeouts matching the retry backoff window","Log resp.StatusCode per attempt to make non-200 failures diagnosable"],"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"}