fish2018/pansou · error

[ ] 执行搜索失败

Error message

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

What it means

Generic wrapper in dyyj.searchImpl for any failure returned by p.executeSearch (which itself may use HTML scraping or the Flarum JSON API). The inner error is preserved via %w, so this is a contextual wrapper, not a distinct failure. It indicates the whole search pipeline for this plugin failed.

Solutions

  1. Inspect the wrapped cause with errors.Unwrap / %v of the returned error — fix the root cause first
  2. Run with debugMode=true to get the pre-wrap log line identifying the failing stage
  3. Verify network access to BaseURL from the host (curl the search URL)
  4. Check whether the site/API changed and update selectors or API params
  5. Ensure doRequestWithRetry backoff is adequate for a rate-limited site

Example fix

// before
results, err := plugin.Search(ctx, keyword)
if err != nil {
	log.Fatal(err)
}
// after
results, err := plugin.Search(ctx, keyword)
if err != nil {
	var rootErr error
	for e := err; e != nil; e = errors.Unwrap(e) {
		rootErr = e
	}
	log.Fatalf("search failed: %v (root cause: %v)", err, rootErr)
}
Defensive patterns

Strategy: try-catch

Validate before calling

url, err := url.Parse(pluginBaseURL); if err != nil || url.Host == "" { return errors.New("plugin base URL invalid") }

Try / catch

results, err := p.searchImpl(ctx, keyword)
if err != nil {
	log.Printf("[%s] search failed: %v", p.Name(), err) // %v shows the full wrap chain
	return nil, err
}

Prevention

When it happens

Trigger: Any underlying cause inside executeSearch: request construction failure, network error after retries, non-200 status, HTML/JSON parse failure, or empty results path that returns an error.

Common situations: Site blocked the client (cloudflare challenge); API endpoint changed; keyword triggers server-side rate limiting; network/proxy outage in the deployment environment.

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/35cce650c703537f. Report an issue: GitHub.

Appendix: source

Thrown at plugin/dyyj/dyyj.go:171

// SearchWithResult 执行搜索并返回包含IsFinal标记的结果
func (p *DyyjPlugin) SearchWithResult(keyword string, ext map[string]interface{}) (model.PluginSearchResult, error) {
	return p.AsyncSearchWithResult(keyword, p.searchImpl, p.MainCacheKey, ext)
}

// searchImpl 搜索实现
func (p *DyyjPlugin) searchImpl(client *http.Client, keyword string, ext map[string]interface{}) ([]model.SearchResult, error) {
	if p.debugMode {
		log.Printf("[DYYJ] 开始搜索: %s", keyword)
	}

	// 第一步:执行搜索获取结果列表
	// 使用优化的客户端(连接池)而不是传入的client
	searchResults, err := p.executeSearch(p.optimizedClient, keyword)
	if err != nil {
		if p.debugMode {
			log.Printf("[DYYJ] 执行搜索失败: %v", err)
		}
		return nil, fmt.Errorf("[%s] 执行搜索失败: %w", p.Name(), err)
	}

	if p.debugMode {
		log.Printf("[DYYJ] 搜索获取到 %d 个结果", len(searchResults))
	}
	// The Flarum API response already includes each relevant post's content and
	// extracted links. Do not fall back to HTML detail pages, which are protected
	// by a Cloudflare challenge.
	if hasInlineLinks(searchResults) {
		return plugin.FilterResultsByKeyword(searchResults, keyword), nil
	}

	// 第二步:先对标题进行关键词过滤,只处理包含关键词的结果(避免不必要的详情页请求)
	titleFilteredResults := p.filterByTitleKeyword(searchResults, keyword)
	if p.debugMode {
		log.Printf("[DYYJ] 标题关键词过滤后剩余 %d 个结果(将只对这些结果获取详情页)", len(titleFilteredResults))
	}

View on GitHub (pinned to beaa561337)