fish2018/pansou · error
Anubis 验证题目无效
Error message
Anubis 验证题目无效
What it means
After unmarshalling, parseAnubisChallenge validates the challenge: id and randomData must be non-empty and difficulty must be 1–7. Otherwise it returns this sentinel error (miosou.go:265), meaning the challenge parsed but is unusable.
Solutions
- Dump the unmarshalled document to see which field is empty/out-of-range and update struct tags if Anubis renamed it.
- Widen the accepted difficulty range only if the upstream server legitimately changed bounds.
- Confirm the server is a real Anubis instance and not a custom/modified deployment.
- Retry — if it's a transiently corrupted page, ensureGate's retries may fetch a clean one.
Example fix
// before
if challenge.Challenge.ID == "" || challenge.Challenge.RandomData == "" || challenge.Rules.Difficulty < 1 || challenge.Rules.Difficulty > 7 {
return anubisChallengeDocument{}, true, fmt.Errorf("Anubis 验证题目无效")
}
// after — log which invariant failed for diagnosability
if challenge.Challenge.ID == "" || challenge.Challenge.RandomData == "" || challenge.Rules.Difficulty < 1 || challenge.Rules.Difficulty > 7 {
return anubisChallengeDocument{}, true, fmt.Errorf("Anubis 验证题目无效: id=%q randomData=%q difficulty=%d",
challenge.Challenge.ID, challenge.Challenge.RandomData, challenge.Rules.Difficulty)
} Defensive patterns
Strategy: validation
Validate before calling
var probe struct {
Challenge struct {
ID string `json:"id"`
RandomData string `json:"randomData"`
} `json:"challenge"`
Rules struct {
Difficulty int `json:"difficulty"`
} `json:"rules"`
}
if err := json.Unmarshal([]byte(html.UnescapeString(blob)), &probe); err != nil {
return err
}
if probe.Challenge.ID == "" || probe.Challenge.RandomData == "" || probe.Rules.Difficulty < 1 || probe.Rules.Difficulty > 7 {
return fmt.Errorf("challenge fields missing or difficulty out of range")
} Type guard
func validAnubisChallenge(c anubisChallengeDocument) bool {
return c.Challenge.ID != "" && c.Challenge.RandomData != "" &&
c.Rules.Difficulty >= 1 && c.Rules.Difficulty <= 7
} Try / catch
challenge, found, err := parseAnubisChallenge(body)
if err != nil {
if strings.Contains(err.Error(), "验证题目无效") {
// server format drift: log document and verify struct tags
}
return err
} Prevention
- Validate challenge fields before starting the PoW loop
- Log which invariant failed (id/randomData/difficulty)
- Test the parser against captured fixtures from the live server
- Confirm the server runs stock Anubis
When it happens
Trigger: JSON unmarshals cleanly into anubisChallengeDocument but Challenge.ID or Challenge.RandomData is empty, or Rules.Difficulty is 0 or >7 — i.e. field-name drift or an upstream format change rather than corrupt JSON.
Common situations: Anubis raising its difficulty range or renaming fields so they unmarshal to zero values; a stub/test Anubis deployment emitting minimal JSON; a proxy serving a cached/partial page.
Understand the failure class
Background: Schema validation failed / invalid input schema: payload rejected because its shape doesn't match the expected schema — this error's family across 28 libraries.
Related errors
AI-assisted analysis of fish2018/pansou@beaa561337 (2026-09-07).
Data as JSON: /api/errors/c70ba61dadb176ea.
Report an issue: GitHub.
Appendix: source
Thrown at plugin/miosou/miosou.go:265
Difficulty int `json:"difficulty"`
} `json:"rules"`
Challenge struct {
ID string `json:"id"`
RandomData string `json:"randomData"`
} `json:"challenge"`
}
func parseAnubisChallenge(body []byte) (anubisChallengeDocument, bool, error) {
match := anubisChallengePattern.FindSubmatch(body)
if len(match) != 2 {
return anubisChallengeDocument{}, false, nil
}
var challenge anubisChallengeDocument
if err := json.Unmarshal([]byte(html.UnescapeString(string(match[1]))), &challenge); err != nil {
return anubisChallengeDocument{}, true, fmt.Errorf("解析 Anubis 验证题目失败: %w", err)
}
if challenge.Challenge.ID == "" || challenge.Challenge.RandomData == "" || challenge.Rules.Difficulty < 1 || challenge.Rules.Difficulty > 7 {
return anubisChallengeDocument{}, true, fmt.Errorf("Anubis 验证题目无效")
}
if challenge.Rules.Algorithm != "fast" && challenge.Rules.Algorithm != "slow" {
return anubisChallengeDocument{}, true, fmt.Errorf("不支持的 Anubis 验证算法: %s", challenge.Rules.Algorithm)
}
return challenge, true, nil
}
func solveAnubisChallenge(ctx context.Context, randomData string, difficulty int) (string, uint64, error) {
prefix := []byte(randomData)
buffer := make([]byte, len(prefix), len(prefix)+20)
copy(buffer, prefix)
for nonce := uint64(0); ; nonce++ {
if nonce&4095 == 0 {
select {
case <-ctx.Done():
return "", 0, fmt.Errorf("计算 Anubis 工作量证明失败: %w", ctx.Err())
default:
}View on GitHub (pinned to beaa561337)