fish2018/pansou · error
web search documents contained no valid links
Error message
web search documents contained no valid links
What it means
searchWeb fetches each candidate item's document concurrently (semaphore of 8) and builds final results. If every fetchPansoDocument call failed to yield a valid link, it raises 'web search documents contained no valid links'. Search results were found, but none could be converted into usable download links.
Solutions
- Log fetchPansoDocument errors per item to see whether failures are HTTP-level or parsing-level.
- Reduce concurrency (semaphore of 8) and add retry/backoff if detail pages are rate-limited.
- Update the detail-page link extraction logic if panso.vip changed its markup.
- Treat some failures as acceptable only when at least one result succeeds; otherwise surface per-item causes.
Example fix
// before
wg.Wait()
if len(results) == 0 {
return nil, fmt.Errorf("web search documents contained no valid links")
}
// after
wg.Wait()
if len(results) == 0 {
return nil, fmt.Errorf("web search documents contained no valid links (items=%d, lastErr=%v)", len(items), firstFetchErr)
} Defensive patterns
Strategy: fallback
Try / catch
results, err := plugin.Search(keyword)
if err != nil && strings.Contains(err.Error(), "no valid links") {
// all detail fetches failed: inspect per-item errors, throttle, or switch source
} Prevention
- Collect and log per-item fetchPansoDocument errors, not just the aggregate
- Throttle detail-page fetches (lower semaphore, add delays) to avoid rate limits
- Retry failed detail fetches individually before declaring total failure
- Keep detail-page link extraction updated against site markup changes
When it happens
Trigger: After wg.Wait() in searchWeb, len(results) == 0 because every fetchPansoDocument call failed or produced a result without links — e.g. all detail pages non-200, or link extraction selectors broken.
Common situations: Detail-page endpoints moved or now require login; pan links expired/removed upstream; concurrency of 8 triggered rate limiting on all detail fetches; link parsing regex/selector outdated.
Understand the failure class
Background: EmptyResultError / "no results found": when an API or scraper succeeds but returns zero rows — this error's family across 9 libraries.
Related errors
AI-assisted analysis of fish2018/pansou@beaa561337 (2026-09-07).
Data as JSON: /api/errors/2fb8af2c99e7c0c8.
Report an issue: GitHub.
Appendix: source
Thrown at plugin/sousou/sousou.go:238
item := item
wg.Add(1)
go func() {
defer wg.Done()
sem <- struct{}{}
defer func() { <-sem }()
result, err := p.fetchPansoDocument(client, item)
if err != nil {
debugLog("document %s failed: %v", item.DocURL, err)
return
}
mu.Lock()
results = append(results, result)
mu.Unlock()
}()
}
wg.Wait()
if len(results) == 0 {
return nil, fmt.Errorf("web search documents contained no valid links")
}
return results, nil
}
func (p *SousouAsyncPlugin) fetchPansoDocument(client *http.Client, item pansoSearchItem) (model.SearchResult, error) {
ctx, cancel := context.WithTimeout(context.Background(), 20*time.Second)
defer cancel()
req, err := http.NewRequestWithContext(ctx, http.MethodGet, item.DocURL, nil)
if err != nil {
return model.SearchResult{}, err
}
setSousouWebHeaders(req, SousouWebURL+"?q=")
resp, err := client.Do(req)
if err != nil {
return model.SearchResult{}, err
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {View on GitHub (pinned to beaa561337)