fish2018/pansou · warning

未知请求错误

Error message

未知请求错误

What it means

Defensive fallback in doRequestWithRetry: if the retry loop finished without recording any error (a code path that should be unreachable because every non-200 sets lastErr), lastErr is initialized to this 'unknown request error' message before the retry-exhausted wrapper is returned.

Solutions

  1. Ensure MaxRetries is a positive constant
  2. Validate retry count at plugin init
  3. Keep the guard but include MaxRetries in the final wrapped message for diagnosis

Example fix

// before
if lastErr == nil {
    lastErr = fmt.Errorf("未知请求错误")
}
// after
if lastErr == nil {
    lastErr = fmt.Errorf("未知请求错误 (MaxRetries=%d)", MaxRetries)
}
Defensive patterns

Strategy: validation

Validate before calling

if MaxRetries <= 0 {
    return errors.New("MaxRetries 必须为正数")
}

Try / catch

if err != nil && strings.Contains(err.Error(), "未知请求错误") {
    log.Printf("重试循环未执行任何有效尝试, MaxRetries=%d", MaxRetries)
}

Prevention

When it happens

Trigger: Retry loop exits with lastErr still nil — e.g. loop structure changes or MaxRetries <= 0 so no attempt is made.

Common situations: Misconfiguration where MaxRetries is 0 or negative, causing the for-loop body never to execute; future refactors altering the loop.

Understand the failure class

Background: "This is a bug, please report it": internal invariant violations, unreachable panics, and SNH errors explained — this error's family across 47 libraries.

Related errors


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

Appendix: source

Thrown at plugin/xdpan/xdpan.go:459

		reqClone := req.Clone(req.Context())

		resp, err := client.Do(reqClone)
		if err != nil {
			lastErr = err
			continue
		}
		if strings.EqualFold(resp.Header.Get("cf-mitigated"), "challenge") {
			resp.Body.Close()
			return nil, fmt.Errorf("站点 %s 已迁移并启用 Cloudflare 浏览器验证,当前服务端请求无法通过", p.baseURL)
		}
		if resp.StatusCode == http.StatusOK {
			return resp, nil
		}
		lastErr = fmt.Errorf("HTTP %d", resp.StatusCode)
		resp.Body.Close()
	}
	if lastErr == nil {
		lastErr = fmt.Errorf("未知请求错误")
	}
	return nil, fmt.Errorf("重试 %d 次后仍然失败: %w", MaxRetries, lastErr)
}

// setRequestHeaders 设置请求头
func (p *XdpanPlugin) setRequestHeaders(req *http.Request) {
	req.Header.Set("User-Agent", UserAgent)
	req.Header.Set("Referer", strings.TrimRight(p.baseURL, "/")+"/?p=baidu")
	req.Header.Set("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8")
	req.Header.Set("Accept-Language", "zh-CN,zh;q=0.9,en;q=0.8")
	req.Header.Set("Connection", "keep-alive")
	req.Header.Set("Cache-Control", "max-age=0")
}

// cacheItem 缓存项结构
type cacheItem struct {
	links     []model.Link
	timestamp time.Time

View on GitHub (pinned to beaa561337)