fish2018/pansou · error

[ ] 创建首页请求失败

Error message

[%s] 创建首页请求失败: %w

What it means

This error is returned by JsNoteClubPlugin.fetchDataKey when http.NewRequestWithContext fails to construct the GET request for https://jsnoteclub.com/. The wrapped error (%w) carries the underlying httpx/net-http construction failure. It means the request could not even be built, before any network I/O happens.

Solutions

  1. Inspect the wrapped error via errors.Unwrap or %v logging to see the exact NewRequest failure reason
  2. Verify no cancelled/expired context is being substituted for context.Background()
  3. Check that the hardcoded URL constant was not modified to an invalid value
  4. Retry the run; if transient environment corruption is suspected, restart the process

Example fix

// before
req, err := http.NewRequestWithContext(ctx, http.MethodGet, "https://jsnoteclub.com/", nil)
if err != nil {
    return "", fmt.Errorf("[%s] 创建首页请求失败: %w", p.Name(), err)
}
// after
req, err := http.NewRequestWithContext(ctx, http.MethodGet, homepageURL, nil)
if err != nil {
    return "", fmt.Errorf("[%s] 创建首页请求失败: %w (url=%q)", p.Name(), err, homepageURL)
}
Defensive patterns

Strategy: try-catch

Try / catch

key, err := plugin.fetchDataKey(client)
if err != nil {
    var reqErr *url.Error
    if errors.As(err, &reqErr) {
        // request construction/transport failure: log and skip or retry later
        return fmt.Errorf("skipping jsnoteclub: %w", err)
    }
    return err
}

Prevention

When it happens

Trigger: http.NewRequestWithContext returns a non-nil error for the fixed URL https://jsnoteclub.com/ — practically only when the context passed to the request is invalid/dead or the http.Client configuration is broken; with a literal valid URL this almost never fires.

Common situations: A parent context that was already cancelled or exceeded its deadline being threaded into context.Background replacement incorrectly; running inside an environment where the http package cannot build requests (rare, e.g. a nil URL from a refactored constant); a build-time regression that changed the hardcoded URL to an unparsable value.

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/1ad106c94a6fbb42. Report an issue: GitHub.

Appendix: source

Thrown at plugin/jsnoteclub/jsnoteclub.go:230

	posts, err := p.fetchPosts(client, dataKey)
	if err != nil {
		return nil, err
	}

	postsCache.entries = posts
	postsCache.expire = time.Now().Add(postsCacheTTL)
	postsCache.key = dataKey

	return posts, nil
}

func (p *JsNoteClubPlugin) fetchDataKey(client *http.Client) (string, error) {
	ctx, cancel := context.WithTimeout(context.Background(), requestTimeout)
	defer cancel()

	req, err := http.NewRequestWithContext(ctx, http.MethodGet, "https://jsnoteclub.com/", nil)
	if err != nil {
		return "", fmt.Errorf("[%s] 创建首页请求失败: %w", p.Name(), err)
	}
	setHTMLHeaders(req, "https://jsnoteclub.com/")

	resp, err := p.doRequestWithRetry(req, client, maxRequestRetries)
	if err != nil {
		return "", fmt.Errorf("[%s] 访问首页失败: %w", p.Name(), err)
	}
	defer resp.Body.Close()

	if resp.StatusCode != http.StatusOK {
		return "", fmt.Errorf("[%s] 首页返回状态码: %d", p.Name(), resp.StatusCode)
	}

	doc, err := goquery.NewDocumentFromReader(resp.Body)
	if err != nil {
		return "", fmt.Errorf("[%s] 解析首页失败: %w", p.Name(), err)
	}

View on GitHub (pinned to beaa561337)