fish2018/pansou · error
[ ] 刷新 buildId 后获取首页失败
Error message
[%s] 刷新 buildId 后获取首页失败: %w
What it means
Recovery-path error in pansearch's doSearch (plugin/pansearch/pansearch.go:525): after a 404 triggered a buildId cache reset, re-fetching the site's base URL/buildId failed again, so the fallback recovery itself failed and the search aborts.
Solutions
- Check the wrapped error to determine whether the retry failed with 404 again or a network/timeout error.
- If 404 persists, the search API URL scheme may have changed — verify against the current upstream frontend requests.
- Retry later with backoff; the issue may be transient upstream instability.
- Capture the request URL used and compare it with the upstream site's live API calls.
Defensive patterns
Strategy: retry
Try / catch
if err != nil && strings.Contains(err.Error(), "刷新 buildId 后获取首页失败") {
// even the retry failed — treat as upstream outage
return err
} Prevention
- Don't retry immediately in a loop; use backoff since the built-in retry already failed
- Verify the search API URL format against the live site when this recurs
- Monitor for persistent failures indicating an API endpoint change
When it happens
Trigger: buildId was refreshed but the retried fetchFirstPage still failed — network error, timeout, another 404, or another non-200 status from the search API.
Common situations: 站点频繁重新部署导致 buildId 连续变化;getBaseURL 解析页面失败。
Understand the failure class
Background: 'Something went wrong' / 'Request failed (500)' / 'HTTP error! status: 404' — what failed HTTP requests actually mean and how to find the real cause — this error's family across 28 libraries.
Related errors
AI-assisted analysis of fish2018/pansou@beaa561337 (2026-09-07).
Data as JSON: /api/errors/4749a7b47fab0a41.
Report an issue: GitHub.
Appendix: source
Thrown at plugin/pansearch/pansearch.go:525
baseURL, err := p.getBaseURL(client)
if err != nil {
return nil, fmt.Errorf("[%s] 获取API基础URL失败: %w", p.Name(), err)
}
firstPageResults, total, err := p.fetchFirstPage(keyword, baseURL, client)
if err != nil {
if strings.Contains(err.Error(), "404") || strings.Contains(err.Error(), "Not Found") {
buildIdMutex.Lock()
buildIdCache = ""
buildIdCacheTime = time.Time{}
buildIdMutex.Unlock()
baseURL, err = p.getBaseURL(client)
if err != nil {
return nil, fmt.Errorf("[%s] 刷新 buildId 失败: %w", p.Name(), err)
}
firstPageResults, total, err = p.fetchFirstPage(keyword, baseURL, client)
if err != nil {
return nil, fmt.Errorf("[%s] 刷新 buildId 后获取首页失败: %w", p.Name(), err)
}
} else {
return nil, fmt.Errorf("[%s] 获取首页失败: %w", p.Name(), err)
}
}
allResults := append([]PanSearchItem(nil), firstPageResults...)
pageCount := min((min(total, p.maxResults)+PageSize-1)/PageSize, MaxAPIPages)
if pageCount > 1 {
type pageResult struct {
offset int
items []PanSearchItem
}
resultCh := make(chan pageResult, pageCount-1)
sem := make(chan struct{}, min(p.maxConcurrent, pageCount-1))
var wg sync.WaitGroup
for page := 1; page < pageCount; page++ {View on GitHub (pinned to beaa561337)