fish2018/pansou · error
[ ] 获取首页失败
Error message
[%s] 获取首页失败: %w
What it means
When the first fetchFirstPage fails for any reason other than a 404, doSearch returns this wrapped error immediately without attempting a buildId refresh. It covers all non-404 failures of the initial search-API call.
Solutions
- Read the wrapped cause: 429/5xx → back off and retry later; connection errors → check network/proxy/DNS.
- Reduce request frequency to avoid rate limiting.
- Verify the upstream search endpoint is reachable from this host (curl the same URL).
- A 404 would have triggered a buildId refresh automatically; for other statuses handle retry logic in the caller.
Example fix
// before
results, err := plugin.Search(ctx, kw)
if err != nil {
return err
}
// after
results, err := plugin.Search(ctx, kw)
if err != nil {
if isRetryable(err) {
time.Sleep(3 * time.Second)
results, err = plugin.Search(ctx, kw)
}
} Defensive patterns
Strategy: retry
Validate before calling
// probe upstream health before searching
resp, err := http.Head("https://www.pansearch.me/")
if err != nil || resp.StatusCode >= 500 {
// skip search, upstream unavailable
} Try / catch
if err != nil && strings.Contains(err.Error(), "获取首页失败") {
if strings.Contains(err.Error(), "context deadline exceeded") {
// timeout: increase timeout and retry
} else if strings.Contains(err.Error(), "429") {
// rate limited: back off significantly
}
} Prevention
- Classify the wrapped cause before choosing a retry strategy
- Back off on 429/5xx instead of hammering the upstream
- Check proxy/DNS config if connection errors persist
When it happens
Trigger: fetchFirstPage failed with a non-404 error: connection refused/reset, timeout, non-200 non-404 status (e.g. 500/503/429), or request-construction error.
Common situations: Upstream outage or maintenance (5xx), rate limiting (429), DNS/proxy misconfiguration, or the host being blocked by the upstream's anti-bot layer.
Understand the failure class
Background: "API request failed": what wrapped HTTP errors from external APIs mean and how to find the real cause — this error's family across 29 libraries.
Related errors
AI-assisted analysis of fish2018/pansou@beaa561337 (2026-09-07).
Data as JSON: /api/errors/0f219976035fab3e.
Report an issue: GitHub.
Appendix: source
Thrown at plugin/pansearch/pansearch.go:528
}
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++ {
offset := page * PageSize
wg.Add(1)
go func() {View on GitHub (pinned to beaa561337)