fish2018/pansou · error
获取搜索结果失败
Error message
获取搜索结果失败: %w
What it means
doSearch fails at step 2: p.getSearchResults(credentials.Sign, 1, client) returned an error while fetching the first page of search results. The Sign credential was obtained, but the search API call itself failed (HTTP error or unparseable response).
Solutions
- Retry the search — transient failures and expired signs typically resolve on a fresh credential fetch.
- Inspect the wrapped error from getSearchResults (status code vs parse error) with DebugLog enabled.
- Verify the site is reachable and the response format matches what the plugin expects.
- Update the plugin if the upstream API changed.
Defensive patterns
Strategy: retry
Validate before calling
if !isSiteReachable(BaseURL) {
return errors.New("panyq upstream unreachable, skip search")
} Try / catch
hits, err := plugin.Search(keyword)
if err != nil && strings.Contains(err.Error(), "获取搜索结果失败") {
time.Sleep(backoff)
hits, err = plugin.Search(keyword) // fresh sign on retry
} Prevention
- Retry once with backoff — signs can expire between fetch and search
- Monitor upstream API format changes
- Avoid hammering the site to prevent IP blocks
- Log wrapped cause for status vs parse distinction
When it happens
Trigger: Calling doSearch when the search endpoint rejects the Sign (expired/invalid credential), returns non-200, or returns malformed JSON that getSearchResults cannot decode.
Common situations: Credential expired between fetching and searching; upstream API changed response format; transient network failure or 5xx; IP blocked/rate limited by the site.
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/34953e8d9e80049f.
Report an issue: GitHub.
Appendix: source
Thrown at plugin/panyq/panyq.go:230
credentials, err := p.getCredentials(keyword, actionIDs[ActionIDKeys[0]], client)
if err != nil {
// 如果获取凭证失败,尝试刷新Action ID并重试
actionIDs, err = p.discoverActionIDs()
if err != nil {
return nil, fmt.Errorf("刷新Action ID失败: %w", err)
}
// 使用新的Action ID重试获取凭证
credentials, err = p.getCredentials(keyword, actionIDs[ActionIDKeys[0]], client)
if err != nil {
return nil, fmt.Errorf("获取搜索凭证失败: %w", err)
}
}
// 步骤2: 获取第一页搜索结果列表
hits, maxPageNum, err := p.getSearchResults(credentials.Sign, 1, client)
if err != nil {
return nil, fmt.Errorf("获取搜索结果失败: %w", err)
}
if len(hits) == 0 {
if DebugLog {
fmt.Println("panyq: no results found for", keyword)
}
return []model.SearchResult{}, nil
}
// 如果有多页结果,并发获取其他页的数据
if maxPageNum > 1 {
if DebugLog {
fmt.Printf("panyq: found %d pages, fetching additional pages...\n", maxPageNum)
}
if maxPageNum >= 3 {
maxPageNum = 3
}
// 创建通道存储其他页的结果View on GitHub (pinned to beaa561337)