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

  1. Simply retry — ensureGate already retries completeAnubisChallenge up to 3 times.
  2. Check for intermediate proxies/firewalls that terminate keep-alive connections.
  3. Increase client read/idle timeouts if they are tighter than server response time.
  4. 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

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)