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

  1. Inspect the logged first-500-chars debug output to see what the API actually returned.
  2. Check whether the API now requires authentication or a different endpoint/headers (User-Agent, Referer).
  3. Confirm the HunhepanResponse struct matches the current API schema (field names and JSON types).
  4. 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

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)