fish2018/pansou · error

detail request failed

Error message

detail request failed: %w

What it means

Wrapped network error in DiscourseAsyncPlugin.GetTopicDetail (plugin/discourse/discourse.go:477): the cloudscraper GET to the topic detail URL failed before any response was produced (DNS, TLS, timeout, or anti-bot challenge failure). No HTTP status exists at this point, so upstream code cannot retry with status-based logic from this error alone.

Solutions

  1. Check the wrapped error to identify DNS/connect/TLS cause
  2. Verify the site URL is correct and reachable in a browser
  3. Confirm cloudscraper solved the Cloudflare challenge (403/503 with cf pages)
  4. Check proxy/VPN and firewall settings
  5. Retry on transient network errors with backoff
Defensive patterns

Strategy: retry

Validate before calling

u, err := url.Parse(detailURL)
if err != nil || u.Scheme == "" || u.Host == "" {
    return fmt.Errorf("invalid detail url: %q", detailURL)
}

Try / catch

links, err := plugin.GetTopicDetail(id)
if err != nil && strings.Contains(err.Error(), "detail request failed") {
    var nerr net.Error
    if errors.As(errors.Unwrap(err), &nerr) && nerr.Timeout() {
        time.Sleep(backoff)
        links, err = plugin.GetTopicDetail(id)
    }
}

Prevention

When it happens

Trigger: p.scraper.Get(detailURL) returns a non-nil error — DNS failure, connection refused/reset, timeout, TLS error, or cloudflare bypass failure.

Common situations: 目标站点不可达、本地网络断开、代理配置错误。

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/8426c9072c0810fb. Report an issue: GitHub.

Appendix: source

Thrown at plugin/discourse/discourse.go:477

	}
	
	return content
}

// GetTopicDetail 获取主题详情(可选实现,用于获取完整链接)
func (p *DiscourseAsyncPlugin) GetTopicDetail(topicID int) ([]model.Link, error) {
	// 检查 cloudscraper 是否初始化成功
	if p.scraper == nil {
		return nil, fmt.Errorf("cloudscraper not initialized")
	}

	// 构建详情URL
	detailURL := fmt.Sprintf(detailURLTemplate, topicID)

	// 发送详情请求
	resp, err := p.scraper.Get(detailURL)
	if err != nil {
		return nil, fmt.Errorf("detail request failed: %w", err)
	}
	defer resp.Body.Close()

	// 检查HTTP状态码
	if resp.StatusCode != 200 {
		return nil, fmt.Errorf("unexpected status code: %d", resp.StatusCode)
	}

	// 读取响应体
	body, err := io.ReadAll(resp.Body)
	if err != nil {
		return nil, fmt.Errorf("read response failed: %w", err)
	}

	// 解析JSON响应
	var detailResp DetailResponse
	if err := json.Unmarshal(body, &detailResp); err != nil {
		return nil, fmt.Errorf("parse json failed: %w", err)

View on GitHub (pinned to beaa561337)