fish2018/pansou · error
解析验证响应失败
Error message
解析验证响应失败: %w
What it means
Wrapped decode error in gying's challenge verification submission (plugin/gying/gying.go:1888): the verification endpoint answered 200 with a body that is not the expected challengeVerifyResponse JSON — typically another challenge page or an HTML error.
Solutions
- Log a snippet of respBody to see what was actually returned.
- Check resp.StatusCode alongside the body; non-200 usually means an HTML error page.
- Update cloudscraper / challenge parsing if the site changed its verify endpoint response.
- Retry; transient HTML interstitials can masquerade as parse failures.
Defensive patterns
Strategy: validation
Validate before calling
if !json.Valid(respBody) { return fmt.Errorf("non-JSON response (status=%d)", resp.StatusCode) } Type guard
var probe map[string]any; if err := json.Unmarshal(respBody, &probe); err != nil || probe["success"] == nil { /* treat as HTML/error page */ } Try / catch
if err != nil { if strings.Contains(err.Error(), "解析验证响应失败") { logBodySnippet(respBody); checkStatusCode(); } } Prevention
- Always log the first bytes of the body on parse failure
- Check HTTP status alongside JSON expectations
- Handle CDN/WAF HTML pages explicitly
- Pin and update the scraping library when sites change APIs
When it happens
Trigger: submitChallengeVerification receives a 200 response whose body is not valid JSON matching challengeVerifyResponse (e.g. an HTML error page with a 200 status).
Common situations: 提交后触发新一轮反爬页面;验证接口结构变更。
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/ee47ae40c18f3329.
Report an issue: GitHub.
Appendix: source
Thrown at plugin/gying/gying.go:1888
return fmt.Errorf("提交验证失败: %w", err)
}
defer resp.Body.Close()
if DebugLog {
fmt.Printf("[Gying] Challenge提交完成: url=%s status=%d\n", requestURL, resp.StatusCode)
}
respBody, err := ioutil.ReadAll(resp.Body)
if err != nil {
return fmt.Errorf("读取验证响应失败: %w", err)
}
if isBotChallengePage(respBody) {
return fmt.Errorf("机器人验证出现循环")
}
var verifyResp challengeVerifyResponse
if err := json.Unmarshal(respBody, &verifyResp); err != nil {
return fmt.Errorf("解析验证响应失败: %w", err)
}
if !verifyResp.Success {
if verifyResp.Msg != "" {
return fmt.Errorf("机器人验证失败: %s", verifyResp.Msg)
}
return fmt.Errorf("机器人验证失败")
}
if DebugLog {
fmt.Printf("[Gying] Challenge验证成功: url=%s\n", requestURL)
}
return nil
}
func (p *GyingPlugin) requestWithChallengeRetry(scraper *cloudscraper.Scraper, method, requestURL, contentType, requestBody string) ([]byte, int, http.Header, error) {
for attempt := 0; attempt < 2; attempt++ {
var (View on GitHub (pinned to beaa561337)