{"record":{"id":"c4565f76872b5c73","repo":"AlistGo/alist","slug":"init-captcha-token-failed-s","errorCode":null,"errorMessage":"init captcha token failed: %s","messagePattern":"init captcha token failed: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"drivers/guangyapan/driver.go","lineNumber":731,"sourceCode":"\tresp, err := d.accountClient.R().\n\t\tSetContext(ctx).\n\t\tSetBody(map[string]any{\n\t\t\t\"client_id\": d.ClientID,\n\t\t\t\"action\":    \"POST:/v1/auth/verification\",\n\t\t\t\"device_id\": d.DeviceID,\n\t\t\t\"meta\": map[string]any{\n\t\t\t\t\"username\":           normalizePhoneE164(d.PhoneNumber),\n\t\t\t\t\"phone_number\":       normalizePhoneE164(d.PhoneNumber),\n\t\t\t\t\"VERIFICATION_PHONE\": normalizePhoneE164(d.PhoneNumber),\n\t\t\t},\n\t\t}).\n\t\tSetResult(&out).\n\t\tPost(\"/v1/shield/captcha/init\")\n\tif err != nil {\n\t\treturn err\n\t}\n\tif resp.IsError() || out.Error != \"\" || strings.TrimSpace(out.CaptchaToken) == \"\" {\n\t\treturn fmt.Errorf(\"init captcha token failed: %s\", d.accountErr(out.ErrorDesc, out.Error, resp))\n\t}\n\td.CaptchaToken = strings.TrimSpace(out.CaptchaToken)\n\td.accountClient.SetHeader(\"X-Captcha-Token\", d.CaptchaToken)\n\top.MustSaveDriverStorage(d)\n\treturn nil\n}\n\nfunc normalizeCaptchaUsername(phone string) string {\n\tp := strings.TrimSpace(phone)\n\tp = strings.ReplaceAll(p, \" \", \"\")\n\tp = strings.TrimPrefix(p, \"+\")\n\t// Keep only digits.\n\tb := make([]rune, 0, len(p))\n\tfor _, ch := range p {\n\t\tif ch >= '0' && ch <= '9' {\n\t\t\tb = append(b, ch)\n\t\t}\n\t}","sourceCodeStart":713,"sourceCodeEnd":749,"githubUrl":"https://github.com/AlistGo/alist/blob/843d9dc8149126976b2625911e45a4d3ffd6f2f5/drivers/guangyapan/driver.go#L713-L749","documentation":"ensureCaptchaToken POSTs a signed captcha init payload (username/phone metadata) to /v1/shield/captcha/init and throws when the response is an HTTP error, has an error field, or the CaptchaToken is empty. On success the token is stored and set as the X-Captcha-Token header on the account client. The captcha token gates subsequent verification/SMS endpoints.","triggerScenarios":"First SMS login attempt (no stored CaptchaToken), or a forced refresh after captcha_invalid; the init is rejected because of malformed phone metadata, an unrecognized device_id, anti-bot heuristics, or provider outage.","commonSituations":"phone_number format that normalizePhoneE164/normalizeCaptchaUsername mangles; signing up from a new device/IP that trips anti-bot; provider-side shield service down or its protocol changed.","solutions":["Confirm phone_number is a valid E164-ish number for the account.","Retry after a minute to let anti-bot/rate limits cool down.","If the protocol changed (e.g. new required fields in the init payload), update the captchaInitResp/request shape in the driver."],"exampleFix":null,"handlingStrategy":"retry","validationCode":"// cheap pre-checks before captcha init\nif d.PhoneNumber == \"\" {\n    return errors.New(\"phone_number required before captcha init\")\n}","typeGuard":null,"tryCatchPattern":"if err := d.ensureCaptchaToken(ctx, true); err != nil {\n    if strings.Contains(err.Error(), \"init captcha token failed\") {\n        // shield/anti-bot: back off and retry once\n        time.Sleep(5 * time.Second)\n        err = d.ensureCaptchaToken(ctx, true)\n    }\n    if err != nil {\n        return fmt.Errorf(\"captcha init rejected (possible anti-bot or outage): %w\", err)\n    }\n}","preventionTips":["Keep a stable device_id in config so the provider trusts the client.","Avoid rapid-fire logins from rotating IPs."],"tags":["auth","captcha","anti-bot","guangyapan"],"backgroundTag":null,"analyzedSha":"843d9dc8149126976b2625911e45a4d3ffd6f2f5","analyzedAt":"2026-08-15T12:14:11.722Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}