fish2018/pansou · error

[ ] 执行搜索失败

Error message

[%s] 执行搜索失败: %w

What it means

searchImpl wraps any failure from p.executeSearch(keyword) with this error, preserving the underlying cause via %w and prefixing the plugin name. It is the outer boundary error for the first phase of a Diduan search: fetching and extracting the result list.

Solutions

  1. Unwrap the error (errors.Unwrap or %w chain) to see whether it was a request failure, HTTP status, or parse failure.
  2. If the message mentions a Cloudflare Managed Challenge, pause and retry later or improve scraper stealth/proxy setup.
  3. Verify BaseURL/SearchPath still match the live site's endpoints.
  4. Add retries/backoff for transient network errors.

Example fix

// before
results, err := p.Search(keyword)
if err != nil { return err }
// after
results, err := p.Search(keyword)
if err != nil {
    log.Printf("diduan search failed: %v", err) // %w chain shows root cause
    return err
}
Defensive patterns

Strategy: try-catch

Try / catch

results, err := p.Search(keyword)
if err != nil {
    log.Printf("search failed: %+v", err) // preserve wrap chain
    if strings.Contains(err.Error(), "Managed Challenge") {
        // cool-down / proxy rotation path
    }
    return err
}

Prevention

When it happens

Trigger: executeSearch returns an error — the page request failed (wrapped 搜索请求失败), a non-200 status or Cloudflare challenge occurred (httpStatusError), or goquery HTML parsing failed — and searchImpl propagates it wrapped.

Common situations: Cloudflare challenge pages returned to the scraper; site layout change causing parse or empty responses; network outages; the search endpoint URL changed so requests 404.

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/1d9e84b472879220. Report an issue: GitHub.

Appendix: source

Thrown at plugin/diduan/diduan.go:139

// SearchWithResult 使用 BaseAsyncPlugin 的缓存和后台刷新能力。
func (p *DiduanPlugin) SearchWithResult(keyword string, ext map[string]interface{}) (model.PluginSearchResult, error) {
	return p.AsyncSearchWithResult(keyword, p.searchImpl, p.MainCacheKey, ext)
}

// searchImpl 搜索实现
func (p *DiduanPlugin) searchImpl(client *http.Client, keyword string, ext map[string]interface{}) ([]model.SearchResult, error) {
	if p.scraper == nil {
		return nil, fmt.Errorf("[%s] Cloudflare 请求客户端未初始化", p.Name())
	}
	if p.debugMode {
		log.Printf("[DIDUAN] 开始搜索: %s", keyword)
	}

	// 第一步:执行搜索获取结果列表
	searchResults, err := p.executeSearch(keyword)
	if err != nil {
		return nil, fmt.Errorf("[%s] 执行搜索失败: %w", p.Name(), err)
	}

	if p.debugMode {
		log.Printf("[DIDUAN] 搜索获取到 %d 个结果", len(searchResults))
	}

	// 第二步:并发获取详情页链接
	finalResults := p.fetchDetailLinks(searchResults, keyword)

	if p.debugMode {
		log.Printf("[DIDUAN] 最终获取到 %d 个有效结果", len(finalResults))
	}

	// 第三步:关键词过滤(标准网盘插件需要过滤)
	filteredResults := plugin.FilterResultsByKeyword(finalResults, keyword)

	if p.debugMode {
		log.Printf("[DIDUAN] 关键词过滤后剩余 %d 个结果", len(filteredResults))

View on GitHub (pinned to beaa561337)