fish2018/pansou · error
[ ] 搜索第一页失败
Error message
[%s] 搜索第一页失败: %w
What it means
CldiPlugin.searchImpl wraps a failure from searchPage on page 1 with the plugin name for context. The wrapped error comes from request creation, request execution, status-code check, body read, or HTML parsing. It signals the initial search page could not be retrieved, so no results are returned.
Solutions
- Inspect the wrapped cause (%w) to determine whether it was request creation, transport, status code, body read, or parsing.
- Test the CLDI search URL manually with curl using the same headers.
- Check for rate limiting or IP blocking; add backoff or proxy rotation.
- Verify the endpoint URL and page-1 parameters are still valid.
Defensive patterns
Strategy: try-catch
Try / catch
results, err := plugin.Search(ctx, keyword)
if err != nil {
if strings.Contains(err.Error(), "搜索第一页失败") {
log.Printf("CLDI first page failed, skipping plugin: %v", err)
// continue with other plugins' results
}
} Prevention
- Treat per-plugin failures as non-fatal and aggregate results from other plugins
- Monitor plugin-specific failure rates to detect blocked endpoints early
- Keep plugin endpoint URLs and headers up to date
- Add health checks per plugin before large batch searches
When it happens
Trigger: p.searchPage(client, keyword, 1) returns an error in searchImpl — e.g. the first page request timed out, was rate-limited, or its HTML couldn't be parsed.
Common situations: The CLDI site is down or blocking the client, network outage, or the search endpoint changed causing repeated failures.
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/c2a8205c3f67d36a.
Report an issue: GitHub.
Appendix: source
Thrown at plugin/cldi/cldi.go:71
func (p *CldiPlugin) Search(keyword string, ext map[string]interface{}) ([]model.SearchResult, error) {
result, err := p.SearchWithResult(keyword, ext)
if err != nil {
return nil, err
}
return result.Results, nil
}
// SearchWithResult 执行搜索并返回包含IsFinal标记的结果
func (p *CldiPlugin) SearchWithResult(keyword string, ext map[string]interface{}) (model.PluginSearchResult, error) {
return p.AsyncSearchWithResult(keyword, p.searchImpl, p.MainCacheKey, ext)
}
// searchImpl 实际的搜索实现
func (p *CldiPlugin) searchImpl(client *http.Client, keyword string, ext map[string]interface{}) ([]model.SearchResult, error) {
// 1. 首先搜索第一页
firstPageResults, err := p.searchPage(client, keyword, 1)
if err != nil {
return nil, fmt.Errorf("[%s] 搜索第一页失败: %w", p.Name(), err)
}
// 存储所有结果
var allResults []model.SearchResult
allResults = append(allResults, firstPageResults...)
// 2. 并发搜索其他页面(第2页到第5页)
if MaxPages > 1 {
var wg sync.WaitGroup
var mu sync.Mutex
// 使用信号量控制并发数
semaphore := make(chan struct{}, MaxConcurrency)
// 存储每页结果
pageResults := make(map[int][]model.SearchResult)
for page := 2; page <= MaxPages; page++ {View on GitHub (pinned to beaa561337)