fish2018/pansou · error

decode response failed

Error message

decode response failed: %w

What it means

Wrapped decode error in jikepan's doSearch (plugin/jikepan/jikepan.go:97): the response body was read fully but json.Unmarshal against JikepanResponse failed, meaning the API returned content in an unexpected shape (HTML error page, changed schema) despite a successful request.

Solutions

  1. Log the HTTP status and first bytes of bodyBytes to see what was actually returned
  2. Check resp.StatusCode before decoding; handle non-200 explicitly
  3. Validate the site is reachable normally (anti-bot/Cloudflare interstitial)
  4. Update JikepanResponse struct to match the current API schema

Example fix

// before
if err := json.Unmarshal(bodyBytes, &apiResp); err != nil {
	return nil, fmt.Errorf("decode response failed: %w", err)
}

// after
if resp.StatusCode != http.StatusOK {
	return nil, fmt.Errorf("jikepan returned status %d: %s", resp.StatusCode, truncate(bodyBytes, 200))
}
if err := json.Unmarshal(bodyBytes, &apiResp); err != nil {
	return nil, fmt.Errorf("decode response failed (status %d): %w", resp.StatusCode, err)
}
Defensive patterns

Strategy: type-guard

Validate before calling

if resp.StatusCode != http.StatusOK {
	return fmt.Errorf("jikepan: unexpected status %d", resp.StatusCode)
}
ct := resp.Header.Get("Content-Type")
if !strings.Contains(ct, "application/json") {
	return fmt.Errorf("jikepan: non-JSON content-type %q", ct)
}

Type guard

func looksLikeJSON(b []byte) bool {
	t := bytes.TrimSpace(b)
	return len(t) > 0 && (t[0] == '{' || t[0] == '[')
}

Try / catch

// Go
results, err := p.doSearch(ctx, keyword, ext)
var uerr *json.UnmarshalTypeError
if errors.As(err, &uerr) {
	log.Printf("jikepan schema drift at %v", uerr.Field)
}

Prevention

When it happens

Trigger: json.Unmarshal(bodyBytes, &apiResp) fails: the API returned HTML (error page/anti-bot challenge), an empty body, or JSON whose types conflict with JikepanResponse fields.

Common situations: 上游返回 HTML 拦截页;响应被代理改写。

Understand the failure class

Background: "failed to unmarshal" / json.Unmarshal errors: why parsing a response into a Go struct fails and how to fix it — this error's family across 23 libraries.

Related errors


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

Appendix: source

Thrown at plugin/jikepan/jikepan.go:97

	req.Header.Set("referer", "https://jikepan.xyz/")
	req.Header.Set("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36")
	
	// 发送请求
	resp, err := client.Do(req)
	if err != nil {
		return nil, fmt.Errorf("request failed: %w", err)
	}
	defer resp.Body.Close()
	
	// 解析响应
	var apiResp JikepanResponse
	bodyBytes, err := io.ReadAll(resp.Body)
	if err != nil {
		return nil, fmt.Errorf("read response body failed: %w", err)
	}
	
	if err := json.Unmarshal(bodyBytes, &apiResp); err != nil {
		return nil, fmt.Errorf("decode response failed: %w", err)
	}
	
	// 检查响应状态
	if apiResp.Msg != "success" {
		return nil, fmt.Errorf("API returned error: %s", apiResp.Msg)
	}
	
	// 转换结果格式
	results := p.convertResults(apiResp.List)
	
	return results, nil
}

// convertResults 将API响应转换为标准SearchResult格式
func (p *JikepanAsyncV2Plugin) convertResults(items []JikepanItem) []model.SearchResult {
	results := make([]model.SearchResult, 0, len(items))
	
	for i, item := range items {

View on GitHub (pinned to beaa561337)