fish2018/pansou · warning
xunlei captcha required
Error message
xunlei captcha required
What it means
The Xunlei (迅雷) captcha-token fetch routine parses the upstream JSON response and, if the response carries a non-empty url field, the service refuses to proceed because Xunlei is demanding a CAPTCHA verification instead of issuing a captcha token. It is a sentinel error signaling that automation hit an anti-bot wall.
Solutions
- Open the returned response.URL in a browser, complete the CAPTCHA, then retry the operation.
- Slow down request rate and add jitter/backoff to avoid triggering the challenge.
- Refresh the Xunlei login session/token — expired sessions often trigger captcha demands.
- Route requests through a residential IP or the user's own credentials rather than a shared datacenter IP.
Example fix
token, err := s.getXunleiCaptchaToken(ctx)
if errors.Is(err, errXunleiCaptchaRequired) {
return nil, fmt.Errorf("captcha needed, visit %s to verify", lastCaptchaURL)
} Defensive patterns
Strategy: fallback
Try / catch
token, err := s.getXunleiCaptchaToken(ctx)
if err != nil && strings.Contains(err.Error(), "captcha required") {
return manualVerificationRequired(err)
} Prevention
- Rate-limit Xunlei requests and add jitter.
- Refresh login tokens before they expire.
- Avoid datacenter IPs known to trigger anti-bot challenges.
When it happens
Trigger: Calling the xunlei captcha-token endpoint returns JSON with a url field set (a CAPTCHA/verification page link) instead of a captcha_token, e.g. after too many automated requests.
Common situations: Rate-limited or IP-flagged Xunlei account; running from a datacenter IP flagged for automation; expired login session forcing re-verification; sudden burst of link checks.
Related errors
AI-assisted analysis of fish2018/pansou@beaa561337 (2026-09-07).
Data as JSON: /api/errors/e9a47434cedb3574.
Report an issue: GitHub.
Appendix: source
Thrown at service/check_service.go:1086
"accept": "application/json;charset=UTF-8",
"content-type": "application/json",
"x-device-id": deviceID,
"x-client-id": clientID,
"x-client-version": clientVersion,
})
if err != nil {
return "", err
}
var response struct {
CaptchaToken string `json:"captcha_token"`
URL string `json:"url"`
}
if err := utiljson.Unmarshal(body, &response); err != nil {
return "", err
}
if response.URL != "" {
return "", fmt.Errorf("xunlei captcha required")
}
return response.CaptchaToken, nil
}
func (s *CheckService) buildResult(item model.CheckItem, normalized string, state string, cacheHit bool, summary string) model.CheckResult {
now := time.Now()
expiresAt := now.Add(ttlForState(state))
return model.CheckResult{
DiskType: item.DiskType,
URL: item.URL,
NormalizedURL: normalized,
State: state,
CacheHit: cacheHit,
CheckedAt: now.UnixMilli(),
ExpiresAt: expiresAt.UnixMilli(),
Summary: summary,
}View on GitHub (pinned to beaa561337)