fish2018/pansou · error

[ ] 获取API基础URL失败

Error message

[%s] 获取API基础URL失败: %w

What it means

doSearch wraps any error from getBaseURL (buildId resolution) with this message. It signals the plugin could not determine the API base URL/buildId, and the wrapped error (non-200 status, body read failure, or buildId not found) is the real cause.

Solutions

  1. Inspect the wrapped cause (%w) — fix the underlying buildId fetch issue first.
  2. Retry after a delay; a successful buildId fetch will be cached and subsequent calls succeed.
  3. Check upstream availability and any rate limiting/blocking (429/403).
  4. Clear the buildId cache if a stale value is suspected and retry.

Example fix

// before
baseURL, err := p.getBaseURL(client)
// after
baseURL, err := p.getBaseURL(client)
if err != nil {
    log.Printf("getBaseURL failed: %v; will retry once", err)
    time.Sleep(time.Second)
    baseURL, err = p.getBaseURL(client)
}
Defensive patterns

Strategy: try-catch

Try / catch

if err != nil && strings.Contains(err.Error(), "获取API基础URL失败") {
    var wrapped error = errors.Unwrap(err) // inspect root cause
    log.Printf("buildId/baseURL resolution failed: %v", wrapped)
    // schedule a retry with backoff
}

Prevention

When it happens

Trigger: Any getBuildId failure — upstream non-200 response, body read error, or buildId extraction failure with no cache — surfacing through doSearch.

Common situations: First-ever call with no cached buildId while the upstream is down/rate-limiting, upstream markup changed, or network egress blocked from the host.

Understand the failure class

Background: "API request failed": what wrapped HTTP errors from external APIs mean and how to find the real cause — this error's family across 29 libraries.

Related errors


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

Appendix: source

Thrown at plugin/pansearch/pansearch.go:509

	return result.Results, nil
}

// SearchWithResult 执行搜索并返回包含IsFinal标记的结果
func (p *PanSearchAsyncPlugin) SearchWithResult(keyword string, ext map[string]interface{}) (model.PluginSearchResult, error) {
	return p.AsyncSearchWithResult(keyword, p.doSearch, p.MainCacheKey, ext)
}

// doSearch 执行具体的搜索逻辑
func (p *PanSearchAsyncPlugin) doSearch(client *http.Client, keyword string, ext map[string]interface{}) ([]model.SearchResult, error) {
	keyword = strings.TrimSpace(keyword)
	if keyword == "" {
		return nil, fmt.Errorf("[%s] 关键词不能为空", p.Name())
	}
	client = p.requestClient(client)

	baseURL, err := p.getBaseURL(client)
	if err != nil {
		return nil, fmt.Errorf("[%s] 获取API基础URL失败: %w", p.Name(), err)
	}

	firstPageResults, total, err := p.fetchFirstPage(keyword, baseURL, client)
	if err != nil {
		if strings.Contains(err.Error(), "404") || strings.Contains(err.Error(), "Not Found") {
			buildIdMutex.Lock()
			buildIdCache = ""
			buildIdCacheTime = time.Time{}
			buildIdMutex.Unlock()
			baseURL, err = p.getBaseURL(client)
			if err != nil {
				return nil, fmt.Errorf("[%s] 刷新 buildId 失败: %w", p.Name(), err)
			}
			firstPageResults, total, err = p.fetchFirstPage(keyword, baseURL, client)
			if err != nil {
				return nil, fmt.Errorf("[%s] 刷新 buildId 后获取首页失败: %w", p.Name(), err)
			}
		} else {

View on GitHub (pinned to beaa561337)