fish2018/pansou · error
[ ] 会话返回状态码
Error message
[%s] 会话返回状态码: %d
What it means
postSessionRaw treats any non-200 HTTP status from the session endpoints as a hard failure and returns this error containing the numeric status code. Unlike the transport error, an actual HTTP response was received but the server rejected the session establishment (challenge fetch or issue call).
Solutions
- Log the response body (currently read into data but not included in the error) to see the server's actual rejection reason.
- Check for rate limiting (429) and add delays/backoff between session attempts.
- If 403, inspect whether required cookies/headers (set by p.setRequestHeaders) match what the site currently expects.
- Retry after a delay for 5xx; the site may be under maintenance.
- Verify the site API hasn't changed (check in browser devtools) if you consistently get 404/410.
Example fix
// before
if resp.StatusCode != http.StatusOK {
return nil, fmt.Errorf("[%s] 会话返回状态码: %d", p.Name(), resp.StatusCode)
}
// after
if resp.StatusCode != http.StatusOK {
return nil, fmt.Errorf("[%s] 会话返回状态码: %d, body: %s", p.Name(), resp.StatusCode, string(data))
} Defensive patterns
Strategy: try-catch
Validate before calling
null
Type guard
null
Try / catch
data, err := p.postSessionRaw(client, path, body)
if err != nil {
var httpErr *HTTPStatusError // if you extend the plugin to use one
if errors.As(err, &httpErr) && httpErr.Code == http.StatusTooManyRequests {
time.Sleep(backoff)
// retry
}
} Prevention
- Include the response body in the error so the server's rejection reason is visible.
- Throttle request rate to avoid 429/403 anti-bot responses.
- Keep request headers (UA, cookies) current with what the site expects.
- Treat 5xx as retryable and 4xx as non-retryable config/anti-bot issues.
When it happens
Trigger: After client.Do succeeds, resp.StatusCode != http.StatusOK when POSTing to /traffic/session/challenge or /traffic/session/issue. Note the error is returned before reading the body, so the response body (which may contain the actual server error reason) is discarded.
Common situations: Site returns 403/429 due to anti-bot protection (the plugin does solve a PoW challenge, but the site may still block), 5xx during server maintenance, or a Cloudflare challenge page replacing the API response.
Understand the failure class
Background: "API error: {status}" and "HTTP 401/403/404/429/5xx" errors: non-2xx HTTP responses explained — this error's family across 27 libraries.
Related errors
AI-assisted analysis of fish2018/pansou@beaa561337 (2026-09-07).
Data as JSON: /api/errors/4cf30353670d690b.
Report an issue: GitHub.
Appendix: source
Thrown at plugin/nsgame/nsgame.go:370
if body != nil {
reader = strings.NewReader(string(body))
}
req, err := http.NewRequestWithContext(ctx, http.MethodPost, baseURL+path, reader)
if err != nil {
return nil, fmt.Errorf("[%s] 创建会话请求失败: %w", p.Name(), err)
}
if body != nil {
req.Header.Set("Content-Type", "application/json")
}
p.setRequestHeaders(req, "https://nsthwj.cn/")
resp, err := client.Do(req)
if err != nil {
return nil, fmt.Errorf("[%s] 会话请求失败: %w", p.Name(), err)
}
defer resp.Body.Close()
data, _ := io.ReadAll(resp.Body)
if resp.StatusCode != http.StatusOK {
return nil, fmt.Errorf("[%s] 会话返回状态码: %d", p.Name(), resp.StatusCode)
}
return data, nil
}
func solveChallenge(challenge string, difficultyBits int) string {
for nonce := int64(0); nonce < 10000000; nonce++ {
sum := sha256.Sum256([]byte(fmt.Sprintf("%s:%d", challenge, nonce)))
fullBytes, remainder := difficultyBits/8, difficultyBits%8
valid := true
for i := 0; i < fullBytes; i++ {
if sum[i] != 0 {
valid = false
break
}
}
if valid && remainder > 0 && sum[fullBytes]>>(8-remainder) != 0 {
valid = false
}View on GitHub (pinned to beaa561337)