fish2018/pansou · error

验证数据无效

Error message

验证数据无效

What it means

solveLegacyHashChallenge validates the legacy hash-cash style challenge before brute-forcing SHA-256 nonces: it needs an ID, a salt, a positive Diff (nonce upper bound), and at least one target hash. This error is returned when any of those is missing or invalid, meaning the challenge page data does not match the expected legacy format.

Solutions

  1. Dump the raw challenge response and the populated ChallengePageData to see which field is missing
  2. Re-fetch a fresh challenge; transient empty responses are common behind proxies
  3. If the site now serves PoW challenges, route to solvePowChallenge instead of the legacy solver
  4. Update ChallengePageData JSON tags to match the current challenge schema

Example fix

// before
if challenge.ID == "" || challenge.Salt == "" || challenge.Diff <= 0 || len(challenge.Challenge) == 0 {
    return fmt.Errorf("验证数据无效")
}
// after (log which field failed)
if challenge.ID == "" || challenge.Salt == "" || challenge.Diff <= 0 || len(challenge.Challenge) == 0 {
    return fmt.Errorf("验证数据无效: id=%q salt=%q diff=%d targets=%d",
        challenge.ID, challenge.Salt, challenge.Diff, len(challenge.Challenge))
}
Defensive patterns

Strategy: validation

Validate before calling

func validLegacyChallenge(c *ChallengePageData) bool {
    return c.ID != "" && c.Salt != "" && c.Diff > 0 && len(c.Challenge) > 0
}
if !validLegacyChallenge(ch) { /* route to PoW solver or re-fetch */ }

Type guard

func isLegacyHashChallenge(c *ChallengePageData) bool {
    return c.ID != "" && c.Salt != "" && c.Diff > 0 && len(c.Challenge) > 0
}

Try / catch

if err := p.solveLegacyHashChallenge(scraper, requestURL, challenge); err != nil {
    if err.Error() == "验证数据无效" {
        return p.solvePowChallenge(scraper, requestURL, challenge) // fallback scheme
    }
    return err
}

Prevention

When it happens

Trigger: The solver is dispatched to solveLegacyHashChallenge with a ChallengePageData where ID=="", Salt=="", Diff<=0, or Challenge (target hash list) is empty.

Common situations: The site migrated from the legacy hash challenge to the PoW scheme but the dispatcher still routes to the legacy solver; JSON field renaming upstream leaves Salt/Diff/Challenge at zero values; an empty or malformed challenge response was parsed without a hard failure.

Understand the failure class

Background: "must not be empty", "cannot be empty" — required-field validation errors across open-source libraries — this error's family across 41 libraries.

Related errors


AI-assisted analysis of fish2018/pansou@beaa561337 (2026-09-07). Data as JSON: /api/errors/619c7b90ff67ba74. Report an issue: GitHub.

Appendix: source

Thrown at plugin/gying/gying.go:1777

		y.Mod(y, modulus)
	}
	elapsed := time.Since(start)

	if DebugLog {
		fmt.Printf("[Gying] PoW Challenge计算完成: id=%s t=%d cost=%s\n",
			challenge.ID, challenge.T, elapsed.Round(time.Millisecond))
	}

	if minSolveTime := 3 * time.Second; elapsed < minSolveTime {
		time.Sleep(minSolveTime - elapsed)
	}

	return y.Text(16), nil
}

func (p *GyingPlugin) solveLegacyHashChallenge(scraper *cloudscraper.Scraper, requestURL string, challenge *ChallengePageData) error {
	if challenge.ID == "" || challenge.Salt == "" || challenge.Diff <= 0 || len(challenge.Challenge) == 0 {
		return fmt.Errorf("验证数据无效")
	}

	if DebugLog {
		fmt.Printf("[Gying] Challenge命中: url=%s id=%s diff=%d targets=%d\n",
			requestURL, challenge.ID, challenge.Diff, len(challenge.Challenge))
	}

	remaining := make(map[string][]int, len(challenge.Challenge))
	nonces := make([]int, len(challenge.Challenge))
	for idx, target := range challenge.Challenge {
		hash := strings.ToLower(target)
		remaining[hash] = append(remaining[hash], idx)
	}

	workerCount := runtime.GOMAXPROCS(0)
	if workerCount < 1 {
		workerCount = 1
	}

View on GitHub (pinned to beaa561337)