fish2018/pansou · error

[ ] 详情请求失败

Error message

[%s] 详情请求失败: %w

What it means

fetchDetail failed to GET the getVideoDetail endpoint for a given video id, wrapping the transport error from doLingjiGET (retries already exhausted). Mirrors the search failure path but for the detail API.

Solutions

  1. Test the exact getVideoDetail URL with curl to see whether the endpoint is reachable
  2. Check the wrapped error for timeout vs connection-refused vs HTTP status
  3. Increase lingjiDetailTimeout / confirm retry count
  4. Validate the doubID before calling fetchDetail to avoid requests the API cannot serve
  5. Update lingjiAPIBase if the domain rotated
Defensive patterns

Strategy: retry

Validate before calling

// Validate the id and endpoint reachability before detail fetch
if doubID <= 0 {
    return fmt.Errorf("非法详情ID: %d", doubID)
}
ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second)
defer cancel()
if !isEndpointReachable(ctx, lingjiAPIBase) {
    return fmt.Errorf("灵集API不可达")
}

Try / catch

item, err := fetchDetail(doubID)
if err != nil {
    if errors.Is(err, context.DeadlineExceeded) || isNetErr(err) {
        if item, rerr := fetchDetail(doubID); rerr == nil {
            return item, nil
        }
    }
    return emptyItem, err
}

Prevention

When it happens

Trigger: doLingjiGET(client, lingjiAPIBase+"getVideoDetail?identity=...&id=<doubID>", lingjiDetailTimeout) failed on all attempts — network outage, DNS failure, timeout, or HTTP-level error raised inside doLingjiGET.

Common situations: API domain offline or blocked; host network issues; lingjiDetailTimeout too small; invalid id causing server to hang or connection reset; proxy misconfiguration.

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

Appendix: source

Thrown at plugin/lingjisp/lingjisp.go:221

	}

	items := resp.Data.Data
	if len(items) == 0 {
		items = resp.Data.List
	}
	return dedupeLingjiItems(items), nil
}

func (p *LingjiPlugin) fetchDetail(client *http.Client, doubID int) (lingjiVideoItem, error) {
	params := url.Values{}
	params.Set("app_id", lingjiAppID)
	params.Set("identity", lingjiIdentity)
	params.Set("id", fmt.Sprintf("%d", doubID))

	apiURL := lingjiAPIBase + "getVideoDetail?" + params.Encode()
	body, err := doLingjiGET(client, apiURL, lingjiDetailTimeout)
	if err != nil {
		return lingjiVideoItem{}, fmt.Errorf("[%s] 详情请求失败: %w", p.Name(), err)
	}

	var resp lingjiDetailResponse
	if err := json.Unmarshal(body, &resp); err != nil {
		return lingjiVideoItem{}, fmt.Errorf("[%s] 解析详情响应失败: %w", p.Name(), err)
	}
	if !resp.Success || resp.Code != http.StatusOK {
		return lingjiVideoItem{}, fmt.Errorf("[%s] 详情接口返回异常: success=%v code=%d", p.Name(), resp.Success, resp.Code)
	}
	return resp.Data, nil
}

func doLingjiGET(client *http.Client, requestURL string, timeout time.Duration) ([]byte, error) {
	var lastErr error

	for attempt := 0; attempt < lingjiMaxRetries; attempt++ {
		ctx, cancel := context.WithTimeout(context.Background(), timeout)
		req, err := http.NewRequestWithContext(ctx, http.MethodGet, requestURL, nil)

View on GitHub (pinned to beaa561337)