fish2018/pansou · error
[ ] 搜索请求失败
Error message
[%s] 搜索请求失败: %w
What it means
ikantv plugin's doSearch throws this when the request execution (p.doRequestWithRetry) fails after retries are exhausted, wrapping the last underlying error. It covers connection, DNS, TLS, and timeout failures, plus any retry-exhaustion sentinel from the retry helper.
Solutions
- Curl the ikantv search URL from the same host to confirm reachability.
- Increase defaultTimeout so slow upstream responses don't exhaust every retry attempt.
- Inspect the wrapped cause (the %w chain) to distinguish timeout vs connection-refused vs DNS failure.
- Check proxy/VPN/firewall settings and set HTTPS_PROXY if the environment routes through one.
- Verify the ikantv API domain is still alive — plugin endpoints for such sites often change; update the configured base URL if so.
Example fix
// before
resp, err := p.doRequestWithRetry(req, client)
if err != nil {
return nil, fmt.Errorf("[%s] 搜索请求失败: %w", p.Name(), err)
}
// after
var netErr net.Error
if errors.As(err, &netErr) && netErr.Timeout() {
return nil, fmt.Errorf("[%s] 搜索请求超时: %w", p.Name(), err)
}
if err != nil {
return nil, fmt.Errorf("[%s] 搜索请求失败: %w", p.Name(), err)
} Defensive patterns
Strategy: retry
Validate before calling
// reachability pre-check before search
u, _ := url.Parse(searchURL)
conn, err := net.DialTimeout("tcp", net.JoinHostPort(u.Hostname(), portOrDefault(u, "443")), 3*time.Second)
if err != nil {
return fmt.Errorf("ikantv host unreachable: %w", err)
}
conn.Close() Try / catch
results, err := p.doSearch(ctx, keyword)
var netErr net.Error
if err != nil && errors.As(err, &netErr) && netErr.Timeout() {
// transient: retry with backoff or extend defaultTimeout
} else if err != nil {
// permanent network failure: skip this source
log.Printf("ikantv unreachable, skipping: %v", err)
} Prevention
- Curl the API host from the deployment environment before rollout
- Size defaultTimeout and retry counts for the upstream's real latency
- Check the wrapped error chain to classify timeout vs DNS vs refused
- Re-verify the plugin's domain periodically — aggregator endpoints rot
When it happens
Trigger: All attempts in doRequestWithRetry fail: the ikantv API host is unreachable, DNS fails, TLS handshake fails, or the defaultTimeout context deadline expires on each attempt.
Common situations: API domain is dead or DNS-poisoned; the site blocks datacenter IPs; timeout too aggressive for the upstream; network outage on the host running the aggregator.
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/bb574b91caf111d6.
Report an issue: GitHub.
Appendix: source
Thrown at plugin/ikantv/ikantv.go:85
}
ctx, cancel := context.WithTimeout(context.Background(), defaultTimeout)
defer cancel()
req, err := http.NewRequestWithContext(ctx, http.MethodGet, searchURL, nil)
if err != nil {
return nil, fmt.Errorf("[%s] 创建请求失败: %w", p.Name(), err)
}
req.Header.Set("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36")
req.Header.Set("Accept", "application/json, text/plain, */*")
req.Header.Set("Accept-Language", "zh-CN,zh;q=0.9,en;q=0.8")
req.Header.Set("Connection", "keep-alive")
req.Header.Set("Referer", defaultReferer)
resp, err := p.doRequestWithRetry(req, client)
if err != nil {
return nil, fmt.Errorf("[%s] 搜索请求失败: %w", p.Name(), err)
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
return nil, fmt.Errorf("[%s] 请求返回状态码: %d", p.Name(), resp.StatusCode)
}
body, err := io.ReadAll(resp.Body)
if err != nil {
return nil, fmt.Errorf("[%s] 读取响应失败: %w", p.Name(), err)
}
var apiResp apiResponse
if err := json.Unmarshal(body, &apiResp); err != nil {
return nil, fmt.Errorf("[%s] JSON解析失败: %w", p.Name(), err)
}
if apiResp.Code != 0 {
return nil, fmt.Errorf("[%s] API错误: %s", p.Name(), apiResp.Message)View on GitHub (pinned to beaa561337)