{"record":{"id":"5cdef9ad7d0e2a2c","repo":"fish2018/pansou","slug":"s-api-url-w","errorCode":null,"errorMessage":"[%s] 获取API基础URL失败: %w","messagePattern":"\\[(.+?)\\] 获取API基础URL失败: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"plugin/pansearch/pansearch.go","lineNumber":509,"sourceCode":"\treturn result.Results, nil\n}\n\n// SearchWithResult 执行搜索并返回包含IsFinal标记的结果\nfunc (p *PanSearchAsyncPlugin) SearchWithResult(keyword string, ext map[string]interface{}) (model.PluginSearchResult, error) {\n\treturn p.AsyncSearchWithResult(keyword, p.doSearch, p.MainCacheKey, ext)\n}\n\n// doSearch 执行具体的搜索逻辑\nfunc (p *PanSearchAsyncPlugin) doSearch(client *http.Client, keyword string, ext map[string]interface{}) ([]model.SearchResult, error) {\n\tkeyword = strings.TrimSpace(keyword)\n\tif keyword == \"\" {\n\t\treturn nil, fmt.Errorf(\"[%s] 关键词不能为空\", p.Name())\n\t}\n\tclient = p.requestClient(client)\n\n\tbaseURL, err := p.getBaseURL(client)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"[%s] 获取API基础URL失败: %w\", p.Name(), err)\n\t}\n\n\tfirstPageResults, total, err := p.fetchFirstPage(keyword, baseURL, client)\n\tif err != nil {\n\t\tif strings.Contains(err.Error(), \"404\") || strings.Contains(err.Error(), \"Not Found\") {\n\t\t\tbuildIdMutex.Lock()\n\t\t\tbuildIdCache = \"\"\n\t\t\tbuildIdCacheTime = time.Time{}\n\t\t\tbuildIdMutex.Unlock()\n\t\t\tbaseURL, err = p.getBaseURL(client)\n\t\t\tif err != nil {\n\t\t\t\treturn nil, fmt.Errorf(\"[%s] 刷新 buildId 失败: %w\", p.Name(), err)\n\t\t\t}\n\t\t\tfirstPageResults, total, err = p.fetchFirstPage(keyword, baseURL, client)\n\t\t\tif err != nil {\n\t\t\t\treturn nil, fmt.Errorf(\"[%s] 刷新 buildId 后获取首页失败: %w\", p.Name(), err)\n\t\t\t}\n\t\t} else {","sourceCodeStart":491,"sourceCodeEnd":527,"githubUrl":"https://github.com/fish2018/pansou/blob/beaa56133755a548ebc51b090b3816e2ae044aa6/plugin/pansearch/pansearch.go#L491-L527","documentation":"doSearch wraps any error from getBaseURL (buildId resolution) with this message. It signals the plugin could not determine the API base URL/buildId, and the wrapped error (non-200 status, body read failure, or buildId not found) is the real cause.","triggerScenarios":"Any getBuildId failure — upstream non-200 response, body read error, or buildId extraction failure with no cache — surfacing through doSearch.","commonSituations":"First-ever call with no cached buildId while the upstream is down/rate-limiting, upstream markup changed, or network egress blocked from the host.","solutions":["Inspect the wrapped cause (%w) — fix the underlying buildId fetch issue first.","Retry after a delay; a successful buildId fetch will be cached and subsequent calls succeed.","Check upstream availability and any rate limiting/blocking (429/403).","Clear the buildId cache if a stale value is suspected and retry."],"exampleFix":"// before\nbaseURL, err := p.getBaseURL(client)\n// after\nbaseURL, err := p.getBaseURL(client)\nif err != nil {\n    log.Printf(\"getBaseURL failed: %v; will retry once\", err)\n    time.Sleep(time.Second)\n    baseURL, err = p.getBaseURL(client)\n}","handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"if err != nil && strings.Contains(err.Error(), \"获取API基础URL失败\") {\n    var wrapped error = errors.Unwrap(err) // inspect root cause\n    log.Printf(\"buildId/baseURL resolution failed: %v\", wrapped)\n    // schedule a retry with backoff\n}","preventionTips":["Check the wrapped cause to distinguish upstream outage from markup changes","Retry with exponential backoff rather than tight loops","Alert on repeated occurrences — indicates the upstream is blocking or redesigned"],"tags":["http","upstream","buildid","wrapped-error"],"backgroundTag":"api-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"}