{"record":{"id":"87316263a28d0f15","repo":"fish2018/pansou","slug":"s-w-873162","errorCode":null,"errorMessage":"[%s] 解析会话响应失败: %w","messagePattern":"\\[(.+?)\\] 解析会话响应失败: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"plugin/nsgame/nsgame.go","lineNumber":342,"sourceCode":"\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\n\tif err := json.Unmarshal(data, &response); err != nil {\n\t\treturn false, fmt.Errorf(\"[%s] 解析会话响应失败: %w\", p.Name(), err)\n\t}\n\tactive, _ := response.Data.(bool)\n\treturn active, nil\n}\n\nfunc (p *NSGameAsyncPlugin) postSessionRaw(client *http.Client, path string, body []byte) ([]byte, error) {\n\tctx, cancel := context.WithTimeout(context.Background(), defaultTimeout)\n\tdefer cancel()\n\tvar reader io.Reader\n\tif body != nil {\n\t\treader = strings.NewReader(string(body))\n\t}\n\treq, err := http.NewRequestWithContext(ctx, http.MethodPost, baseURL+path, reader)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"[%s] 创建会话请求失败: %w\", p.Name(), err)\n\t}\n\tif body != nil {\n\t\treq.Header.Set(\"Content-Type\", \"application/json\")","sourceCodeStart":324,"sourceCodeEnd":360,"githubUrl":"https://github.com/fish2018/pansou/blob/beaa56133755a548ebc51b090b3816e2ae044aa6/plugin/nsgame/nsgame.go#L324-L360","documentation":"postSession unmarshals the raw bytes returned by postSessionRaw into nsgameSessionResponse to learn whether the session is active; this error means those bytes are not valid JSON for that struct. Since postSessionRaw already returns a 200 body, this points to a non-JSON body (HTML challenge/interstitial) or a changed session-response schema.","triggerScenarios":"Session status endpoint returns an HTML login/WAF page instead of JSON, an empty body, or JSON whose data field no longer matches nsgameSessionResponse (e.g. data changed from bool to object).","commonSituations":"Anti-bot cookies were cleared or expired so the site serves a challenge page; site update altered the session response envelope; an intermediary proxy returns its own error page.","solutions":["Log the raw body from postSessionRaw on unmarshal failure to see the actual content","Update nsgameSessionResponse to match the current schema (especially the interface{} Data field's new shape)","Ensure the challenge/issue steps succeeded and cookies (client.Jar) are retained before querying session status","Re-run ensureSession from scratch if cookies were lost","Check for a proxy stripping/rewriting the response"],"exampleFix":"// before\nif err := json.Unmarshal(data, &response); err != nil {\n    return false, fmt.Errorf(\"[%s] 解析会话响应失败: %w\", p.Name(), err)\n}\n// after\nif err := json.Unmarshal(data, &response); err != nil {\n    return false, fmt.Errorf(\"[%s] 解析会话响应失败(响应开头: %.80q): %w\", p.Name(), data, err)\n}","handlingStrategy":"validation","validationCode":"// before trusting session status, ensure the response is JSON\nif len(data) > 0 && data[0] != '{' {\n    return false, fmt.Errorf(\"session endpoint returned non-JSON body\")\n}","typeGuard":null,"tryCatchPattern":"ok, err := plugin.CheckSession()\nif err != nil {\n    log.Warn(\"session status unknown, re-establishing\", \"err\", err)\n    if rerr := plugin.RefreshSession(); rerr != nil {\n        return rerr\n    }\n}","preventionTips":["Keep the cookie jar intact across requests — losing cookies triggers HTML challenge pages","Validate bodies start with '{' before unmarshalling session responses","Update nsgameSessionResponse when the site changes its session API shape","Re-run the full challenge/issue flow when a status parse fails"],"tags":["json","session","parsing","go"],"backgroundTag":"json-unmarshal-failed","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"}