{"record":{"id":"9d3fd3b834b415f0","repo":"fish2018/pansou","slug":"s-w-9d3fd3","errorCode":null,"errorMessage":"[%s] 搜索第一页失败: %w","messagePattern":"\\[(.+?)\\] 搜索第一页失败: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"plugin/clmao/clmao.go","lineNumber":104,"sourceCode":"func (p *ClmaoPlugin) Search(keyword string, ext map[string]interface{}) ([]model.SearchResult, error) {\n\tresult, err := p.SearchWithResult(keyword, ext)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn result.Results, nil\n}\n\n// SearchWithResult 执行搜索并返回包含IsFinal标记的结果\nfunc (p *ClmaoPlugin) SearchWithResult(keyword string, ext map[string]interface{}) (model.PluginSearchResult, error) {\n\treturn p.AsyncSearchWithResult(keyword, p.searchImpl, p.MainCacheKey, ext)\n}\n\n// searchImpl 实际的搜索实现\nfunc (p *ClmaoPlugin) searchImpl(client *http.Client, keyword string, ext map[string]interface{}) ([]model.SearchResult, error) {\n\t// 1. 首先搜索第一页\n\tfirstPageResults, err := p.searchPage(client, keyword, 1)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"[%s] 搜索第一页失败: %w\", p.Name(), err)\n\t}\n\n\t// 存储所有结果\n\tvar allResults []model.SearchResult\n\tallResults = append(allResults, firstPageResults...)\n\n\t// 2. 并发搜索其他页面（第2页到第5页）\n\tif MaxPages > 1 {\n\t\tvar wg sync.WaitGroup\n\t\tvar mu sync.Mutex\n\n\t\t// 使用信号量控制并发数\n\t\tsemaphore := make(chan struct{}, MaxConcurrency)\n\n\t\t// 存储每页结果\n\t\tpageResults := make(map[int][]model.SearchResult)\n\n\t\tfor page := 2; page <= MaxPages; page++ {","sourceCodeStart":86,"sourceCodeEnd":122,"githubUrl":"https://github.com/fish2018/pansou/blob/beaa56133755a548ebc51b090b3816e2ae044aa6/plugin/clmao/clmao.go#L86-L122","documentation":"ClmaoPlugin.searchImpl wraps any failure from fetching the first page of results (p.searchPage(client, keyword, 1)) with the plugin name for context. It means the very first page request — request creation, HTTP round trip, status check, body read, HTML parse, or nested retry exhaustion — failed, so the multi-page aggregation aborts before appending any results.","triggerScenarios":"Calling the clmao plugin's Search entry point when p.searchPage(client, keyword, 1) returns an error: http.NewRequestWithContext fails, doRequestWithRetry exhausts retries, response status != 200, io.ReadAll fails, goquery parse fails — all get re-wrapped here as \"[clmao] 搜索第一页失败: %w\".","commonSituations":"The site is temporarily unreachable or rate-limiting the client; a site redesign makes the response a non-200 or unparseable page (CAPTCHA/anti-bot interstitial); the request context (TimeoutSeconds) expires before the response arrives.","solutions":["Unwrap the inner error to see which underlying step failed (request creation, HTTP, status code, body read, HTML parse).","Retry the search after a delay — transient network issues and rate limiting are the most common causes.","If status-code errors recur, check the site in a browser; update headers/cookies in setRequestHeaders to bypass anti-bot changes.","Increase TimeoutSeconds if timeouts occur on a slow endpoint.","Handle partial results gracefully if business logic allows instead of failing the entire search."],"exampleFix":"// before\nfirstPageResults, err := p.searchPage(client, keyword, 1)\nif err != nil {\n    return nil, fmt.Errorf(\"[%s] 搜索第一页失败: %w\", p.Name(), err)\n}\n// after\nfirstPageResults, err := p.searchPage(client, keyword, 1)\nif err != nil {\n    if isTransient(err) { time.Sleep(backoff); return p.searchPage(client, keyword, 1) }\n    return nil, fmt.Errorf(\"[%s] 搜索第一页失败: %w\", p.Name(), err)\n}","handlingStrategy":"try-catch","validationCode":"// verify keyword non-empty before calling search\nif strings.TrimSpace(keyword) == \"\" { return nil, errors.New(\"keyword required\") }","typeGuard":null,"tryCatchPattern":"results, err := p.searchImpl(client, keyword, ext)\nif err != nil {\n    log.Printf(\"clmao first-page search failed: %v\", err)\n    return nil, err // or degraded results\n}","preventionTips":["Always unwrap and log the inner error; this is a wrapper around several failure modes.","Watch for site redesigns — first-page parse failures usually mean markup changed.","Throttle request frequency to avoid triggering anti-bot responses.","Keep plugin timeout (TimeoutSeconds) generous enough for slow responses."],"tags":["network","http","scraping","wrapper-error"],"backgroundTag":"api-request-failed","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"}