fish2018/pansou · error
PoW验证数据无效: N
Error message
PoW验证数据无效: N
What it means
computePowResult parses the challenge's RSA-like modulus N from hex via big.Int.SetString before repeatedly squaring x mod N. This error is returned when N is empty, not valid hex, or parses to zero or a negative number, so the modular squaring loop cannot run safely. It indicates the challenge payload delivered by the site is malformed or was not populated.
Solutions
- Log challenge.N (and the raw response body) before calling computePowResult to confirm what the server actually returned
- Re-fetch a fresh challenge from /res/pow; a stale or truncated challenge is the usual cause
- If the site changed its payload shape, update ChallengePageData's JSON field mapping for N
- Reject the challenge client-side before calling the solver: validate N is non-empty hex with a positive value
Example fix
// before
modulus, ok := new(big.Int).SetString(challenge.N, 16)
// after (guard upstream too)
if challenge.N == "" || challenge.T <= 0 {
return fmt.Errorf("PoW验证数据无效: N")
}
modulus, ok := new(big.Int).SetString(strings.TrimPrefix(challenge.N, "0x"), 16) Defensive patterns
Strategy: validation
Validate before calling
func validHexPositive(s string) bool {
n, ok := new(big.Int).SetString(strings.TrimPrefix(s, "0x"), 16)
return ok && n.Sign() > 0
}
if !validHexPositive(ch.N) { /* re-fetch challenge before solving */ } Type guard
func isValidPowModulus(c *ChallengePageData) bool {
n, ok := new(big.Int).SetString(c.N, 16)
return ok && n != nil && n.Sign() > 0
} Try / catch
y, err := p.computePowResult(challenge)
if err != nil {
if strings.Contains(err.Error(), "PoW验证数据无效") {
return p.refetchAndSolve(scraper, requestURL) // re-fetch fresh challenge
}
return err
} Prevention
- Always fetch a fresh challenge immediately before solving; never reuse cached ChallengePageData
- Log the raw challenge response body when DebugLog is enabled
- Validate N/X/T right after json.Unmarshal, before dispatching to a solver
When it happens
Trigger: solvePowChallenge or the direct /res/pow path calls computePowResult with a ChallengePageData whose N field is not a non-empty, positive hex string (e.g. N="", N="xyz", N="0" or N="-1").
Common situations: The upstream bot-protection endpoint changed its response schema so the modulus arrives under a different JSON key; a proxy or captive portal returned HTML/garbage that partially matched the JSON; a cached/stale challenge object was reused after its fields were cleared.
Understand the failure class
Background: "Invalid ... format", "must be in format X", "does not look like a ..." — invalid argument format errors across CLI tools and libraries — this error's family across 17 libraries.
Related errors
AI-assisted analysis of fish2018/pansou@beaa561337 (2026-09-07).
Data as JSON: /api/errors/123699a4d08b7753.
Report an issue: GitHub.
Appendix: source
Thrown at plugin/gying/gying.go:1740
func (p *GyingPlugin) solvePowChallenge(scraper *cloudscraper.Scraper, requestURL string, challenge *ChallengePageData) error {
y, err := p.computePowResult(challenge)
if err != nil {
return err
}
form := url.Values{}
form.Set("action", "verify")
form.Set("id", challenge.ID)
form.Set("y", y)
return p.submitChallengeVerification(scraper, requestURL, form)
}
func (p *GyingPlugin) computePowResult(challenge *ChallengePageData) (string, error) {
modulus, ok := new(big.Int).SetString(challenge.N, 16)
if !ok || modulus.Sign() <= 0 {
return "", fmt.Errorf("PoW验证数据无效: N")
}
y, ok := new(big.Int).SetString(challenge.X, 16)
if !ok || y.Sign() < 0 {
return "", fmt.Errorf("PoW验证数据无效: x")
}
if challenge.T <= 0 {
return "", fmt.Errorf("PoW验证数据无效: t")
}
if DebugLog {
fmt.Printf("[Gying] PoW Challenge计算开始: id=%s t=%d nBits=%d\n",
challenge.ID, challenge.T, modulus.BitLen())
}
start := time.Now()
for i := 0; i < challenge.T; i++ {
y.Mul(y, y)View on GitHub (pinned to beaa561337)