fish2018/pansou · error
[ ] 刷新 buildId 失败
Error message
[%s] 刷新 buildId 失败: %w
What it means
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.
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.
Defensive patterns
Strategy: retry
Try / catch
if err != nil && strings.Contains(err.Error(), "刷新 buildId 失败") {
// refresh failed: wait longer before next attempt
time.Sleep(10 * time.Second)
results, err = plugin.Search(ctx, kw)
} Prevention
- 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
When it happens
Trigger: 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.
Common situations: Upstream rotated its buildId and is simultaneously rate-limiting or serving a challenge page, so the forced re-fetch cannot obtain a fresh buildId.
Related errors
AI-assisted analysis of fish2018/pansou@beaa561337 (2026-09-07).
Data as JSON: /api/errors/7da37494acf965e1.
Report an issue: GitHub.
Appendix: source
Thrown at plugin/pansearch/pansearch.go:521
return nil, fmt.Errorf("[%s] 关键词不能为空", p.Name())
}
client = p.requestClient(client)
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)View on GitHub (pinned to beaa561337)