{"record":{"id":"d1fce1ab6c4fddfe","repo":"fish2018/pansou","slug":"s-w-d1fce1","errorCode":null,"errorMessage":"[%s] 搜索请求失败: %w","messagePattern":"\\[(.+?)\\] 搜索请求失败: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"plugin/ouge/ouge.go","lineNumber":142,"sourceCode":"\tdefer cancel()\n\t\n\treq, err := http.NewRequestWithContext(ctx, \"GET\", searchURL, nil)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"[%s] 创建搜索请求失败: %w\", p.Name(), err)\n\t}\n\t\n\t// 设置请求头\n\treq.Header.Set(\"User-Agent\", \"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36\")\n\treq.Header.Set(\"Accept\", \"application/json, text/plain, */*\")\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(\"Referer\", \"https://woog.nxog.eu.org/\")\n\treq.Header.Set(\"Cache-Control\", \"no-cache\")\n\t\n\t// 发送请求\n\tresp, err := p.doRequestWithRetry(req, client)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"[%s] 搜索请求失败: %w\", p.Name(), err)\n\t}\n\tdefer resp.Body.Close()\n\t\n\t// 解析JSON响应\n\tbody, err := io.ReadAll(resp.Body)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"[%s] 读取响应失败: %w\", p.Name(), err)\n\t}\n\t\n\tvar apiResponse OugeAPIResponse\n\tif err := json.Unmarshal(body, &apiResponse); err != nil {\n\t\treturn nil, fmt.Errorf(\"[%s] 解析JSON响应失败: %w\", p.Name(), err)\n\t}\n\t\n\t// 检查API响应状态\n\tif apiResponse.Code != 1 {\n\t\treturn nil, fmt.Errorf(\"[%s] API返回错误: %s\", p.Name(), apiResponse.Msg)\n\t}","sourceCodeStart":124,"sourceCodeEnd":160,"githubUrl":"https://github.com/fish2018/pansou/blob/beaa56133755a548ebc51b090b3816e2ae044aa6/plugin/ouge/ouge.go#L124-L160","documentation":"The ouge plugin wraps any error returned by its retrying HTTP request layer into a plugin-tagged error via fmt.Errorf with %w. It means the search request to https://woog.nxog.eu.org/ could not be completed after all internal retries. The wrapped cause (DNS failure, timeout, connection refused, non-200 after retries) is preserved and should be inspected with errors.Unwrap or errors.As.","triggerScenarios":"searchImpl calls p.doRequestWithRetry(req, client) and that returns non-nil err: network unreachable, DNS resolution failure, TLS errors, timeouts, or repeated non-200 responses (which become 'HTTP状态码: %d' and are themselves wrapped here).","commonSituations":"The woog.nxog.eu.org mirror is down or blocked in the user's region; no internet/DNS in a container; corporate proxy intercepts TLS; server rate-limits and returns 403/429 on every attempt.","solutions":["Inspect the wrapped cause with errors.Unwrap(err) or log the full chain to see if it is DNS, timeout, or an HTTP status error","Verify network connectivity to https://woog.nxog.eu.org/ with curl from the same host","If status-code errors dominate, check for IP bans/rate limiting and use a proxy or updated base URL","Increase the HTTP client timeout if the cause is a context/deadline exceeded"],"exampleFix":"// before\nresults, err := plugin.Search(keyword)\nif err != nil { return err }\n// after\nresults, err := plugin.Search(keyword)\nif err != nil {\n    var httpErr interface{ Unwrap() error }\n    if errors.As(err, &httpErr) { log.Printf(\"cause: %v\", errors.Unwrap(err)) }\n    return fmt.Errorf(\"ouge search unavailable: %w\", err)\n}","handlingStrategy":"retry","validationCode":"// check connectivity before calling\nfunc checkOugeReachable() error {\n    c, err := net.DialTimeout(\"tcp\", \"woog.nxog.eu.org:443\", 3*time.Second)\n    if err != nil { return err }\n    c.Close()\n    return nil\n}","typeGuard":null,"tryCatchPattern":"if err != nil {\n    var netErr net.Error\n    if errors.As(err, &netErr) && netErr.Timeout() {\n        return fallbackSearch(keyword) // alternate plugin\n    }\n    log.Printf(\"ouge search failed: %v (cause: %v)\", err, errors.Unwrap(err))\n    return err\n}","preventionTips":["Pre-flight check host reachability before batch searches","Always unwrap and log the %w cause for diagnosis","Keep a fallback search plugin for when this upstream is down","Monitor for status-code-heavy failures indicating IP bans"],"tags":["network","http","plugin","wrapped-error"],"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"}