fish2018/pansou · error

[ ] 搜索请求失败

Error message

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

What it means

The encrypted POST to {apiBaseURL}/{URLVersion}/search failed at the transport/request level: requestJSON returned an error (network failure, timeout, non-decodable body, etc.). The plugin wraps the underlying error so callers see it was the search request that failed, distinct from a non-200 search response.

Solutions

  1. Inspect the wrapped error for the root cause (DNS, timeout, TLS, status, decode)
  2. Verify config.URLVersion is current and the versioned /search endpoint exists
  3. Increase the HTTP client timeout or add retries with backoff for transient failures
  4. Check network/proxy connectivity to p.apiBaseURL

Example fix

// before
client := &http.Client{} // no timeout, hangs
// after
client := &http.Client{Timeout: 15 * time.Second} // fail fast, then retry transient errors
Defensive patterns

Strategy: retry

Validate before calling

u, err := url.Parse(fmt.Sprintf("%s/%s/search", apiBaseURL, url.PathEscape(config.URLVersion)))
if err != nil || u.Host == "" {
    return fmt.Errorf("invalid search endpoint URL")
}

Try / catch

items, err := p.search(ctx, client, cfg, kw)
if err != nil {
    var nerr net.Error
    if errors.As(err, &nerr) && (nerr.Timeout() || isTransient(nerr)) {
        return retry.WithBackoff(ctx, 3, p.search, ctx, client, cfg, kw)
    }
    return err
}

Prevention

When it happens

Trigger: p.requestJSON(ctx, client, http.MethodPost, endpoint, encrypted, &response) returns non-nil error in search, where endpoint = p.apiBaseURL+"/"+url.PathEscape(config.URLVersion)+"/search".

Common situations: Network outage, DNS failure, or proxy blocking the search host; request timeout configured too low; an invalid URLVersion produces a 404 or malformed URL; TLS certificate problems; server 5xx with a non-JSON body that requestJSON cannot decode.

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

Appendix: source

Thrown at plugin/yingso/yingso.go:227

func (p *YingsoPlugin) search(ctx context.Context, client *http.Client, config apiConfig, keyword string) ([]searchItem, error) {
	payload := searchPayload{
		PageSize: pageSize,
		PageNum:  1,
		Title:    keyword,
		Root:     0,
		Category: "all",
		UserID:   config.UserID,
	}
	encrypted, err := encryptPayload(payload, config)
	if err != nil {
		return nil, fmt.Errorf("[%s] 生成搜索参数失败: %w", p.Name(), err)
	}

	var response apiEnvelope[[]searchItem]
	endpoint := fmt.Sprintf("%s/%s/search", p.apiBaseURL, url.PathEscape(config.URLVersion))
	if err := p.requestJSON(ctx, client, http.MethodPost, endpoint, encrypted, &response); err != nil {
		return nil, fmt.Errorf("[%s] 搜索请求失败: %w", p.Name(), err)
	}
	if response.Code != http.StatusOK {
		return nil, fmt.Errorf("[%s] 搜索接口异常: code=%d msg=%s", p.Name(), response.Code, response.Msg)
	}
	return response.Data, nil
}

func (p *YingsoPlugin) resolveItem(ctx context.Context, client *http.Client, config apiConfig, item searchItem) (model.SearchResult, error) {
	payload := getKeyPayload{ID: item.ID, UserID: config.UserID}
	encrypted, err := encryptPayload(payload, config)
	if err != nil {
		return model.SearchResult{}, err
	}

	var response apiEnvelope[string]
	endpoint := fmt.Sprintf("%s/%s/getKey", p.apiBaseURL, url.PathEscape(config.URLVersion))
	if err := p.requestJSON(ctx, client, http.MethodPost, endpoint, encrypted, &response); err != nil {
		return model.SearchResult{}, err

View on GitHub (pinned to beaa561337)