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

  1. Log challenge.N (and the raw response body) before calling computePowResult to confirm what the server actually returned
  2. Re-fetch a fresh challenge from /res/pow; a stale or truncated challenge is the usual cause
  3. If the site changed its payload shape, update ChallengePageData's JSON field mapping for N
  4. 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

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)