{"record":{"id":"e9a47434cedb3574","repo":"fish2018/pansou","slug":"xunlei-captcha-required","errorCode":null,"errorMessage":"xunlei captcha required","messagePattern":"xunlei captcha required","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"service/check_service.go","lineNumber":1086,"sourceCode":"\t\t\"accept\":           \"application/json;charset=UTF-8\",\n\t\t\"content-type\":     \"application/json\",\n\t\t\"x-device-id\":      deviceID,\n\t\t\"x-client-id\":      clientID,\n\t\t\"x-client-version\": clientVersion,\n\t})\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\n\tvar response struct {\n\t\tCaptchaToken string `json:\"captcha_token\"`\n\t\tURL          string `json:\"url\"`\n\t}\n\tif err := utiljson.Unmarshal(body, &response); err != nil {\n\t\treturn \"\", err\n\t}\n\tif response.URL != \"\" {\n\t\treturn \"\", fmt.Errorf(\"xunlei captcha required\")\n\t}\n\treturn response.CaptchaToken, nil\n}\n\nfunc (s *CheckService) buildResult(item model.CheckItem, normalized string, state string, cacheHit bool, summary string) model.CheckResult {\n\tnow := time.Now()\n\texpiresAt := now.Add(ttlForState(state))\n\n\treturn model.CheckResult{\n\t\tDiskType:      item.DiskType,\n\t\tURL:           item.URL,\n\t\tNormalizedURL: normalized,\n\t\tState:         state,\n\t\tCacheHit:      cacheHit,\n\t\tCheckedAt:     now.UnixMilli(),\n\t\tExpiresAt:     expiresAt.UnixMilli(),\n\t\tSummary:       summary,\n\t}","sourceCodeStart":1068,"sourceCodeEnd":1104,"githubUrl":"https://github.com/fish2018/pansou/blob/beaa56133755a548ebc51b090b3816e2ae044aa6/service/check_service.go#L1068-L1104","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"token, err := s.getXunleiCaptchaToken(ctx)\nif errors.Is(err, errXunleiCaptchaRequired) {\n    return nil, fmt.Errorf(\"captcha needed, visit %s to verify\", lastCaptchaURL)\n}","handlingStrategy":"fallback","validationCode":null,"typeGuard":null,"tryCatchPattern":"token, err := s.getXunleiCaptchaToken(ctx)\nif err != nil && strings.Contains(err.Error(), \"captcha required\") {\n    return manualVerificationRequired(err)\n}","preventionTips":["Rate-limit Xunlei requests and add jitter.","Refresh login tokens before they expire.","Avoid datacenter IPs known to trigger anti-bot challenges."],"tags":["captcha","anti-bot","xunlei"],"backgroundTag":"captcha-required","analyzedSha":"beaa56133755a548ebc51b090b3816e2ae044aa6","analyzedAt":"2026-09-07T00:31:18.025Z","contentChangedAt":"2026-09-07T00:31:18.025Z","schemaVersion":2},"datasetVersion":"2026-09-15T23:17:13.987Z"}