fish2018/pansou · error

[ ] 创建搜索请求失败

Error message

[%s] 创建搜索请求失败: %w

What it means

executeSearchWithRateLimit returns '[javdb] 创建搜索请求失败: %w' (failed to create search request) when http.NewRequestWithContext cannot construct the GET request for the search URL. In Go this only happens for an invalid URL/method, and the plugin propagates the wrapped stdlib error.

Solutions

  1. Escape the keyword with url.QueryEscape before building searchURL
  2. Validate/normalize the base search URL configured for the plugin
  3. Log the exact searchURL on failure to spot malformed characters
  4. Reject or sanitize keywords containing control characters before searching

Example fix

// before
searchURL := baseURL + "/search?q=" + keyword
// after
searchURL := baseURL + "/search?q=" + url.QueryEscape(keyword)
Defensive patterns

Strategy: validation

Validate before calling

// Go: validate the URL is parseable before issuing the request
u, err := url.Parse(searchURL)
if err != nil || u.Scheme == "" || u.Host == "" {
    return fmt.Errorf("invalid search URL: %q", searchURL)
}

Type guard

func isValidURL(s string) bool {
    u, err := url.Parse(s)
    return err == nil && u.Scheme != "" && u.Host != ""
}

Try / catch

req, err := http.NewRequestWithContext(ctx, "GET", searchURL, nil)
if err != nil {
    return nil, fmt.Errorf("bad search url %q: %w", searchURL, err), false
}

Prevention

When it happens

Trigger: The constructed searchURL fails http.NewRequestWithContext parsing — e.g. the URL contains unescaped characters (control chars, spaces, invalid percent-encoding) because the raw keyword was interpolated without url.QueryEscape.

Common situations: User-submitted search keywords containing spaces, '#', '%', or newlines concatenated directly into the URL; config override producing a malformed base URL.

Understand the failure class

Background: "Invalid URL" / "URL cannot be empty": fix the malformed or missing URL behind request-construction failures — this error's family across 50 libraries.

Related errors


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

Appendix: source

Thrown at plugin/javdb/javdb.go:177

		// 显示重试配置信息
		if MaxRetryOnRateLimit > 0 {
			log.Printf("[JAVDB] 429重试配置: 最大%d次,延迟%d-%d秒", MaxRetryOnRateLimit, MinRetryDelay, MaxRetryDelay)
		} else {
			log.Printf("[JAVDB] 429重试配置: 禁用重试")
		}
		// 如果之前有限流,显示统计信息
		if count := atomic.LoadInt32(&p.rateLimitCount); count > 0 {
			log.Printf("[JAVDB] 历史429限流次数: %d", count)
		}
	}

	// 创建带超时的上下文
	ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
	defer cancel()

	req, err := http.NewRequestWithContext(ctx, "GET", searchURL, nil)
	if err != nil {
		return nil, fmt.Errorf("[%s] 创建搜索请求失败: %w", p.Name(), err), false
	}

	// 设置完整的请求头
	req.Header.Set("User-Agent", UserAgent)
	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("Upgrade-Insecure-Requests", "1")
	req.Header.Set("Cache-Control", "max-age=0")
	req.Header.Set("Referer", BaseURL+"/")

	if p.debugMode {
		log.Printf("[JAVDB] 发送搜索请求...")
	}

	resp, err := client.Do(req)
	if err != nil {
		return nil, fmt.Errorf("[%s] 搜索请求失败: %w", p.Name(), err), false

View on GitHub (pinned to beaa561337)