fish2018/pansou · error

page search failed

Error message

page %d search failed: %w

What it means

yunso's Search fans out one goroutine per page; each goroutine calls searchPage and, on any failure, sends a wrapped error into errChan. This message means page N of the paginated search failed; the underlying cause (network, status, parse, API error) is carried by %w. Other pages may still have succeeded — results and errors are collected concurrently.

Solutions

  1. Read the wrapped cause to see which stage failed (request, status, decode, api error, parse)
  2. Retry only the failed pages instead of the whole search
  3. Check whether the keyword triggers an API-side error (api returned error) and adjust the query
  4. Add per-page retry with backoff before pushing into errChan
  5. Verify network access to www.yunso.net and its API endpoints

Example fix

// before
items, err := p.searchPage(client, keyword, pageNum)
if err != nil {
    errChan <- fmt.Errorf("page %d search failed: %w", pageNum, err)
    return
}
// after
var items []YunsoItem
var err error
for attempt := 0; attempt < 3; attempt++ {
    items, err = p.searchPage(client, keyword, pageNum)
    if err == nil { break }
    time.Sleep(time.Duration(attempt+1) * time.Second)
}
if err != nil {
    errChan <- fmt.Errorf("page %d search failed: %w", pageNum, err)
    return
}
Defensive patterns

Strategy: try-catch

Try / catch

items, err := plugin.Search(ctx, keyword)
if err != nil {
    var pageErr *PageError
    if errors.As(err, &pageErr) {
        log.Warn("partial page failure", "page", pageErr.Page, "cause", pageErr.Unwrap())
    }
    // fall back to partial results already received from resultChan
}

Prevention

When it happens

Trigger: Any searchPage failure for a given pageNum: HTTP request creation/transport error, non-200 status, body read/decode failure, apiResp.Code != 0, or HTML parse failure, all wrapped as "page N search failed".

Common situations: yunso.net is rate-limiting mid-search so later pages fail, the search API returns an error code (e.g. keyword blocked), or transient network drops cause some pages to fail while others succeed.

Understand the failure class

Background: 'Something went wrong' / 'Request failed (500)' / 'HTTP error! status: 404' — what failed HTTP requests actually mean and how to find the real cause — this error's family across 28 libraries.

Related errors


AI-assisted analysis of fish2018/pansou@beaa561337 (2026-09-07). Data as JSON: /api/errors/06f660cfcbc3eabd. Report an issue: GitHub.

Appendix: source

Thrown at plugin/yunso/yunso.go:108

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

// doSearch 实际搜索实现
func (p *YunsoAsyncPlugin) doSearch(client *http.Client, keyword string, ext map[string]interface{}) ([]model.SearchResult, error) {
	resultChan := make(chan []YunsoItem, yunsoDefaultMaxPages)
	errChan := make(chan error, yunsoDefaultMaxPages)

	var wg sync.WaitGroup
	for page := 1; page <= yunsoDefaultMaxPages; page++ {
		wg.Add(1)
		go func(pageNum int) {
			defer wg.Done()

			items, err := p.searchPage(client, keyword, pageNum)
			if err != nil {
				errChan <- fmt.Errorf("page %d search failed: %w", pageNum, err)
				return
			}
			resultChan <- items
		}(page)
	}

	go func() {
		wg.Wait()
		close(resultChan)
		close(errChan)
	}()

	var allItems []YunsoItem
	for items := range resultChan {
		allItems = append(allItems, items...)
	}

	var errs []error

View on GitHub (pinned to beaa561337)