fish2018/pansou · error

[ ] 刷新 buildId 失败

Error message

[%s] 刷新 buildId 失败: %w

What it means

When fetchFirstPage returns a 404 (expired buildId), doSearch clears the buildId cache and calls getBaseURL again to refresh it. If that refresh fails, this error wraps the cause and the search aborts.

Solutions

  1. Look at the wrapped error to see why the refresh failed (status code, read error, or missing buildId).
  2. Wait and retry later — after backoff the upstream may serve a valid page again.
  3. Reduce request rate to avoid 403/429 during the refresh cycle.
  4. Update headers/cookies or extraction logic if the upstream markup/anti-bot behavior changed.
Defensive patterns

Strategy: retry

Try / catch

if err != nil && strings.Contains(err.Error(), "刷新 buildId 失败") {
    // refresh failed: wait longer before next attempt
    time.Sleep(10 * time.Second)
    results, err = plugin.Search(ctx, kw)
}

Prevention

When it happens

Trigger: fetchFirstPage hit a 404 Not Found (stale buildId), triggering a refresh whose getBaseURL call then failed — upstream non-200, body read error, or no buildId in the new response with an empty cache.

Common situations: Upstream rotated its buildId and is simultaneously rate-limiting or serving a challenge page, so the forced re-fetch cannot obtain a fresh buildId.

Related errors


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

Appendix: source

Thrown at plugin/pansearch/pansearch.go:521

		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 {
			return nil, fmt.Errorf("[%s] 获取首页失败: %w", p.Name(), err)
		}
	}

	allResults := append([]PanSearchItem(nil), firstPageResults...)
	pageCount := min((min(total, p.maxResults)+PageSize-1)/PageSize, MaxAPIPages)
	if pageCount > 1 {
		type pageResult struct {
			offset int
			items  []PanSearchItem
		}
		resultCh := make(chan pageResult, pageCount-1)

View on GitHub (pinned to beaa561337)