fish2018/pansou · error
读取 Anubis 验证题目失败
Error message
读取 Anubis 验证题目失败: %w
What it means
After the challenge page is fetched, the body is read with io.ReadAll(io.LimitReader(resp.Body, 1<<20)) (1 MiB cap). This error wraps a read failure of that response body (miosou.go:167), e.g. the connection dropping mid-response or a read deadline firing.
Solutions
- Simply retry — ensureGate already retries completeAnubisChallenge up to 3 times.
- Check for intermediate proxies/firewalls that terminate keep-alive connections.
- Increase client read/idle timeouts if they are tighter than server response time.
- If persistent, check whether the server is rate-limiting or closing connections (server-side logs/status page).
Defensive patterns
Strategy: retry
Try / catch
if err := p.ensureGate(); err != nil {
if strings.Contains(err.Error(), "读取 Anubis 验证题目失败") {
// transient body read failure: retry with backoff
}
return err
} Prevention
- Retry transient read errors with exponential backoff
- Avoid flaky proxies that drop keep-alive connections
- Set sane client timeouts
- Reuse a single well-configured http.Client with connection pooling
When it happens
Trigger: io.ReadAll fails while streaming the challenge HTML: connection reset, unexpected EOF, TLS read error, or server closing the connection before the body completes.
Common situations: Flaky mobile/unstable networks, the Anubis server closing connections under load, an aggressive proxy cutting long responses, or LB idle timeouts.
Understand the failure class
Background: "failed to read file", EACCES, ENOENT and "could not read <path>" errors: when a program can't read a file from disk — this error's family across 49 libraries.
Related errors
AI-assisted analysis of fish2018/pansou@beaa561337 (2026-09-07).
Data as JSON: /api/errors/9629d3e97f9f2d2b.
Report an issue: GitHub.
Appendix: source
Thrown at plugin/miosou/miosou.go:167
lastErr = err
}
return fmt.Errorf("[%s] 人机验证未通过: %w", p.Name(), lastErr)
}
func (p *MiosouPlugin) completeAnubisChallenge(ctx context.Context) error {
req, err := http.NewRequestWithContext(ctx, http.MethodGet, baseURL+"/", nil)
if err != nil {
return fmt.Errorf("创建 Anubis 验证请求失败: %w", err)
}
setPageHeaders(req)
resp, err := p.client.Do(req)
if err != nil {
return fmt.Errorf("获取 Anubis 验证题目失败: %w", err)
}
body, readErr := io.ReadAll(io.LimitReader(resp.Body, 1<<20))
resp.Body.Close()
if readErr != nil {
return fmt.Errorf("读取 Anubis 验证题目失败: %w", readErr)
}
challenge, found, err := parseAnubisChallenge(body)
if err != nil {
return err
}
if !found {
if resp.StatusCode == http.StatusOK && !isAnubisGateResponse(resp) {
return nil
}
return fmt.Errorf("Anubis 验证页返回状态码 %d", resp.StatusCode)
}
startedAt := time.Now()
hash, nonce, err := solveAnubisChallenge(ctx, challenge.Challenge.RandomData, challenge.Rules.Difficulty)
if err != nil {
return err
}
elapsed := time.Since(startedAt).Milliseconds()View on GitHub (pinned to beaa561337)