fish2018/pansou · error

[ ] 搜索失败: ;刷新接口标识失败

Error message

[%s] 搜索失败: %v;刷新接口标识失败: %w

What it means

This error is returned by XiaokupanPlugin.searchImpl when the initial search against xiaokupan.com's TanStack server function endpoint fails AND the automatic recovery path (re-discovering the server function ID from the site's homepage and entry JS bundle) also fails. It wraps the original search error (%v) and the refresh error (%w) so both root causes are visible in one message.

Solutions

  1. Check network connectivity/DNS to xiaokupan.com (curl https://xiaokupan.com/) — most often both errors share the same network root cause
  2. Inspect the wrapped refresh error to see whether discovery failed at homepage fetch, asset lookup, or hash extraction
  3. If the site redeployed, verify the /assets/index-*.js regex and hash extraction logic in discoverServerFunctionID still match the live bundle
  4. Retry after a short delay; if the site is under maintenance the error is transient
  5. Update defaultServerFunctionID to the hash currently embedded in the site's entry JS as a stopgap

Example fix

// before: opaque chained failure
return nil, fmt.Errorf("[%s] 搜索失败: %v;刷新接口标识失败: %w", p.Name(), err, refreshErr)
// after: surface both causes explicitly and retry once before giving up
if refreshErr != nil {
    return nil, fmt.Errorf("xiaokupan: search failed: %v; function-id refresh failed: %w", err, refreshErr)
}
Defensive patterns

Strategy: fallback

Validate before calling

func canReachXiaokupan() error {
    resp, err := http.Head("https://xiaokupan.com/")
    if err != nil { return err }
    defer resp.Body.Close()
    if resp.StatusCode != http.StatusOK { return fmt.Errorf("homepage HTTP %d", resp.StatusCode) }
    return nil
}

Try / catch

results, err := plugin.SearchWithResult(keyword, ext)
if err != nil {
    var wrapped interface{ Unwrap() error }
    log.Printf("xiaokupan search and function-id refresh both failed: %v", err) // inspect %v part for original cause
    return fallbackOtherPlugins(keyword)
}

Prevention

When it happens

Trigger: searchWithFunctionID returns an error for the cached functionID (network failure, HTTP non-200, stale/discontinued function ID hash, oversized response, parse failure), and then refreshServerFunctionID -> discoverServerFunctionID also errors (homepage unreachable, entry script pattern no longer matches, hash not found, or the same network/HTTP problems).

Common situations: xiaokupan.com redeployed its frontend so the baked-in defaultServerFunctionID (sha hash) is stale; the site is down or behind a firewall/proxy; the HTML layout changed so the regex /assets/index-*.js no longer matches; transient DNS/timeouts affecting both requests.

Related errors


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

Appendix: source

Thrown at plugin/xiaokupan/xiaokupan.go:99

func (p *XiaokupanPlugin) SearchWithResult(keyword string, ext map[string]interface{}) (model.PluginSearchResult, error) {
	return p.AsyncSearchWithResult(keyword, p.searchImpl, p.MainCacheKey, ext)
}

func (p *XiaokupanPlugin) searchImpl(client *http.Client, keyword string, _ map[string]interface{}) ([]model.SearchResult, error) {
	keyword = cleanText(keyword)
	if keyword == "" {
		return []model.SearchResult{}, nil
	}
	if client == nil {
		client = http.DefaultClient
	}

	functionID := p.currentServerFunctionID()
	results, err := p.searchWithFunctionID(client, keyword, functionID)
	if err != nil {
		refreshedID, refreshErr := p.refreshServerFunctionID(client, functionID)
		if refreshErr != nil {
			return nil, fmt.Errorf("[%s] 搜索失败: %v;刷新接口标识失败: %w", p.Name(), err, refreshErr)
		}
		results, err = p.searchWithFunctionID(client, keyword, refreshedID)
	}
	if err != nil {
		return nil, fmt.Errorf("[%s] 搜索失败: %w", p.Name(), err)
	}
	return plugin.FilterResultsByKeyword(results, keyword), nil
}

func (p *XiaokupanPlugin) searchWithFunctionID(client *http.Client, keyword, functionID string) ([]model.SearchResult, error) {
	payload, err := buildSearchPayload(keyword)
	if err != nil {
		return nil, fmt.Errorf("构造搜索参数失败: %w", err)
	}

	endpoint := fmt.Sprintf("%s/_serverFn/%s", strings.TrimRight(p.baseURL, "/"), functionID)
	parsedEndpoint, err := url.Parse(endpoint)
	if err != nil {

View on GitHub (pinned to beaa561337)