{"record":{"id":"7da37494acf965e1","repo":"fish2018/pansou","slug":"s-buildid-w","errorCode":null,"errorMessage":"[%s] 刷新 buildId 失败: %w","messagePattern":"\\[(.+?)\\] 刷新 buildId 失败: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"plugin/pansearch/pansearch.go","lineNumber":521,"sourceCode":"\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 {\n\t\t\treturn nil, fmt.Errorf(\"[%s] 获取首页失败: %w\", p.Name(), err)\n\t\t}\n\t}\n\n\tallResults := append([]PanSearchItem(nil), firstPageResults...)\n\tpageCount := min((min(total, p.maxResults)+PageSize-1)/PageSize, MaxAPIPages)\n\tif pageCount > 1 {\n\t\ttype pageResult struct {\n\t\t\toffset int\n\t\t\titems  []PanSearchItem\n\t\t}\n\t\tresultCh := make(chan pageResult, pageCount-1)","sourceCodeStart":503,"sourceCodeEnd":539,"githubUrl":"https://github.com/fish2018/pansou/blob/beaa56133755a548ebc51b090b3816e2ae044aa6/plugin/pansearch/pansearch.go#L503-L539","documentation":"When fetchFirstPage returns a 404 (expired buildId), doSearch clears the buildId cache and calls getBaseURL again to refresh it. If that refresh fails, this error wraps the cause and the search aborts.","triggerScenarios":"fetchFirstPage hit a 404 Not Found (stale buildId), triggering a refresh whose getBaseURL call then failed — upstream non-200, body read error, or no buildId in the new response with an empty cache.","commonSituations":"Upstream rotated its buildId and is simultaneously rate-limiting or serving a challenge page, so the forced re-fetch cannot obtain a fresh buildId.","solutions":["Look at the wrapped error to see why the refresh failed (status code, read error, or missing buildId).","Wait and retry later — after backoff the upstream may serve a valid page again.","Reduce request rate to avoid 403/429 during the refresh cycle.","Update headers/cookies or extraction logic if the upstream markup/anti-bot behavior changed."],"exampleFix":null,"handlingStrategy":"retry","validationCode":null,"typeGuard":null,"tryCatchPattern":"if err != nil && strings.Contains(err.Error(), \"刷新 buildId 失败\") {\n    // refresh failed: wait longer before next attempt\n    time.Sleep(10 * time.Second)\n    results, err = plugin.Search(ctx, kw)\n}","preventionTips":["Throttle request rate — this path fires when upstream both rotates buildId and rejects requests","Increase delay between automatic retries","Keep plugin version current so header/extraction changes are picked up"],"tags":["http","retry","buildid","upstream"],"backgroundTag":"api-error-response","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"}