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
- Log the HTTP status and first bytes of bodyBytes to see what was actually returned
- Check resp.StatusCode before decoding; handle non-200 explicitly
- Validate the site is reachable normally (anti-bot/Cloudflare interstitial)
- 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
- Check status code and Content-Type before decoding
- Log a body snippet on decode failure
- Keep JikepanResponse in sync with API docs
- Use json.Decoder for streaming/disallow-unknown-fields control
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)