{"record":{"id":"481db1f7a2ea73d5","repo":"fish2018/pansou","slug":"s-481db1","errorCode":null,"errorMessage":"[%s] 获取访问挑战失败","messagePattern":"\\[(.+?)\\] 获取访问挑战失败","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"plugin/nsgame/nsgame.go","lineNumber":322,"sourceCode":"\treq.Header.Set(\"X-Client-Viewport\", \"1920x1080\")\n\treq.Header.Set(\"X-Client-Screen\", \"1920x1080@1\")\n}\n\nfunc (p *NSGameAsyncPlugin) ensureSession(client *http.Client) error {\n\tstatus, err := p.postSession(client, \"/traffic/session/status\", nil)\n\tif err != nil {\n\t\treturn err\n\t}\n\tif status {\n\t\treturn nil\n\t}\n\tchallengeBody, err := p.postSessionRaw(client, \"/traffic/session/challenge\", nil)\n\tif err != nil {\n\t\treturn err\n\t}\n\tvar challenge nsgameChallengeResponse\n\tif err := json.Unmarshal(challengeBody, &challenge); err != nil || !challenge.Success || challenge.Data.Challenge == \"\" {\n\t\treturn fmt.Errorf(\"[%s] 获取访问挑战失败\", p.Name())\n\t}\n\tnonce := solveChallenge(challenge.Data.Challenge, challenge.Data.DifficultyBits)\n\tif nonce == \"\" {\n\t\treturn fmt.Errorf(\"[%s] 计算访问挑战失败\", p.Name())\n\t}\n\tissueBody, _ := json.Marshal(map[string]string{\"challenge\": challenge.Data.Challenge, \"nonce\": nonce})\n\tif _, err := p.postSessionRaw(client, \"/traffic/session/issue\", issueBody); err != nil {\n\t\treturn err\n\t}\n\treturn nil\n}\n\nfunc (p *NSGameAsyncPlugin) postSession(client *http.Client, path string, body []byte) (bool, error) {\n\tdata, err := p.postSessionRaw(client, path, body)\n\tif err != nil {\n\t\treturn false, err\n\t}\n\tvar response nsgameSessionResponse","sourceCodeStart":304,"sourceCodeEnd":340,"githubUrl":"https://github.com/fish2018/pansou/blob/beaa56133755a548ebc51b090b3816e2ae044aa6/plugin/nsgame/nsgame.go#L304-L340","documentation":"ensureSession requests a proof-of-work challenge from /traffic/session/challenge and validates the reply; this error means the challenge endpoint failed at the protocol level — JSON was malformed, success was false, or the challenge string was empty. Without a valid challenge the plugin cannot mint a nonce and obtain a session, so the search aborts.","triggerScenarios":"Challenge endpoint returns HTML/empty body (json.Unmarshal fails), returns success=false (blocked/IP banned), or returns a JSON shape where data.challenge is missing/empty after a site API change.","commonSituations":"The site's anti-bot layer (e.g. Vaptcha-like traffic shield) changed its response format, the client IP is blacklisted, Cloudflare intercepts the challenge endpoint, or the site is under maintenance.","solutions":["Log the raw challengeBody on failure to see whether it's HTML (WAF) or an error JSON","Compare the response shape against nsgameChallengeResponse and update the struct if the site changed fields","Retry with backoff — challenge endpoints intermittently fail under load","Test from a different IP; if another IP works, the current IP is rate-limited or banned","Check whether nsthwj.cn moved the anti-bot endpoints and update the paths"],"exampleFix":"// before\nif err := json.Unmarshal(challengeBody, &challenge); err != nil || !challenge.Success || challenge.Data.Challenge == \"\" {\n    return fmt.Errorf(\"[%s] 获取访问挑战失败\", p.Name())\n}\n// after\nif err := json.Unmarshal(challengeBody, &challenge); err != nil {\n    return fmt.Errorf(\"[%s] 获取访问挑战失败: 解析错误(响应开头: %.80q): %w\", p.Name(), challengeBody, err)\n} else if !challenge.Success || challenge.Data.Challenge == \"\" {\n    return fmt.Errorf(\"[%s] 获取访问挑战失败: success=%v, challenge=%q\", p.Name(), challenge.Success, challenge.Data.Challenge)\n}","handlingStrategy":"retry","validationCode":null,"typeGuard":null,"tryCatchPattern":"results, err := plugin.Search(keyword, ext)\nif err != nil && strings.Contains(err.Error(), \"获取访问挑战失败\") {\n    time.Sleep(2 * time.Second)\n    results, err = plugin.Search(keyword, ext) // challenge endpoints are often transiently flaky\n}","preventionTips":["Retry challenge acquisition with jittered backoff","Log raw challenge responses to detect WAF/HTML interception immediately","Update the challenge response struct whenever the site changes its anti-bot vendor","Test from multiple IPs to distinguish bans from transient failures"],"tags":["anti-bot","session","proof-of-work","go"],"backgroundTag":"unexpected-response-shape","analyzedSha":"beaa56133755a548ebc51b090b3816e2ae044aa6","analyzedAt":"2026-09-07T00:31:18.025Z","contentChangedAt":"2026-09-07T00:31:18.025Z","schemaVersion":2},"datasetVersion":"2026-09-15T23:17:13.987Z"}