fish2018/pansou · error
decode response failed
Error message
decode response failed (page %d): %w
What it means
Hunhepan plugin throws this when json.Unmarshal(respBody, &apiResp) fails while decoding a page's body into HunhepanResponse. It means the response bytes are not valid JSON or do not match the expected struct (e.g. wrong JSON types for fields).
Solutions
- Inspect the logged first-500-chars debug output to see what the API actually returned.
- Check whether the API now requires authentication or a different endpoint/headers (User-Agent, Referer).
- Confirm the HunhepanResponse struct matches the current API schema (field names and JSON types).
- Add a content-type check before unmarshalling to fail fast on HTML responses.
Example fix
// before
if err := json.Unmarshal(respBody, &apiResp); err != nil {
errChan <- fmt.Errorf("decode response failed (page %d): %w", pageNum, err)
return
}
// after
if err := json.Unmarshal(respBody, &apiResp); err != nil {
var unmarshalErr *json.UnmarshalTypeError
if errors.As(err, &unmarshalErr) {
errChan <- fmt.Errorf("decode response failed (page %d): field %s type mismatch: %w", pageNum, unmarshalErr.Field, err)
} else {
errChan <- fmt.Errorf("decode response failed (page %d): %w", pageNum, err)
}
return
} Defensive patterns
Strategy: type-guard
Validate before calling
// after obtaining the raw response, before trusting JSON
ct := resp.Header.Get("Content-Type")
if !strings.Contains(ct, "application/json") {
return fmt.Errorf("unexpected content-type %q — API likely served HTML/auth page", ct)
} Type guard
func looksLikeJSON(b []byte) bool {
t := bytes.TrimSpace(b)
return len(t) > 0 && (t[0] == '{' || t[0] == '[')
} Try / catch
results, err := plugin.Search(ctx, keyword)
var pe *json.UnmarshalTypeError
if err != nil && errors.As(err, pe) == (pe != nil) {
// schema/type mismatch: log the debug body dump and check API contract changes
} else if err != nil {
log.Printf("hunhepan decode failed (schema or auth page?): %v", err)
} Prevention
- Check the logged first-500-chars output to identify HTML vs JSON responses
- Keep the response struct in sync with the live API schema
- Validate content-type before unmarshalling
- Re-test plugins after upstream site updates — schemas change without notice
When it happens
Trigger: The API returns HTML (login page, error page, CAPTCHA), an empty body, truncated JSON, or JSON whose field types differ from HunhepanResponse (e.g. code as string instead of number).
Common situations: API endpoint moved or now requires auth cookies; an anti-bot WAF serves HTML; the site changed its response schema after a plugin update; CDN serves an error page.
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/bb3869e8c1396900.
Report an issue: GitHub.
Appendix: source
Thrown at plugin/hunhepan/hunhepan.go:257
defer resp.Body.Close()
debugLog("收到响应 (page %d), 状态码: %d", pageNum, resp.StatusCode)
// 读取响应体
respBody, err := io.ReadAll(resp.Body)
if err != nil {
debugLog("读取响应失败 (page %d): %v", pageNum, err)
errChan <- fmt.Errorf("read response body failed (page %d): %w", pageNum, err)
return
}
debugLog("响应内容 (page %d, 前500字符): %s", pageNum, string(respBody[:min(500, len(respBody))]))
// 解析响应
var apiResp HunhepanResponse
if err := json.Unmarshal(respBody, &apiResp); err != nil {
debugLog("JSON解析失败 (page %d): %v", pageNum, err)
errChan <- fmt.Errorf("decode response failed (page %d): %w", pageNum, err)
return
}
// 检查响应状态
if apiResp.Code != 200 {
debugLog("API返回错误 (page %d): code=%d, msg=%s", pageNum, apiResp.Code, apiResp.Msg)
errChan <- fmt.Errorf("API returned error (page %d): %s", pageNum, apiResp.Msg)
return
}
debugLog("成功获取第 %d 页数据,共 %d 条结果", pageNum, len(apiResp.Data.List))
// 将结果发送到通道
resultChan <- apiResp.Data.List
}(page)
}
// 启动一个goroutine等待所有页面请求完成并关闭通道View on GitHub (pinned to beaa561337)