AlistGo/alist · error

init captcha token failed: %s

Error message

init captcha token failed: %s

What it means

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.

Source

Thrown at drivers/guangyapan/driver.go:731

	resp, err := d.accountClient.R().
		SetContext(ctx).
		SetBody(map[string]any{
			"client_id": d.ClientID,
			"action":    "POST:/v1/auth/verification",
			"device_id": d.DeviceID,
			"meta": map[string]any{
				"username":           normalizePhoneE164(d.PhoneNumber),
				"phone_number":       normalizePhoneE164(d.PhoneNumber),
				"VERIFICATION_PHONE": normalizePhoneE164(d.PhoneNumber),
			},
		}).
		SetResult(&out).
		Post("/v1/shield/captcha/init")
	if err != nil {
		return err
	}
	if resp.IsError() || out.Error != "" || strings.TrimSpace(out.CaptchaToken) == "" {
		return fmt.Errorf("init captcha token failed: %s", d.accountErr(out.ErrorDesc, out.Error, resp))
	}
	d.CaptchaToken = strings.TrimSpace(out.CaptchaToken)
	d.accountClient.SetHeader("X-Captcha-Token", d.CaptchaToken)
	op.MustSaveDriverStorage(d)
	return nil
}

func normalizeCaptchaUsername(phone string) string {
	p := strings.TrimSpace(phone)
	p = strings.ReplaceAll(p, " ", "")
	p = strings.TrimPrefix(p, "+")
	// Keep only digits.
	b := make([]rune, 0, len(p))
	for _, ch := range p {
		if ch >= '0' && ch <= '9' {
			b = append(b, ch)
		}
	}

View on GitHub (pinned to 843d9dc814)

Solutions

  1. Confirm phone_number is a valid E164-ish number for the account.
  2. Retry after a minute to let anti-bot/rate limits cool down.
  3. If the protocol changed (e.g. new required fields in the init payload), update the captchaInitResp/request shape in the driver.
Defensive patterns

Strategy: retry

Validate before calling

// cheap pre-checks before captcha init
if d.PhoneNumber == "" {
    return errors.New("phone_number required before captcha init")
}

Try / catch

if err := d.ensureCaptchaToken(ctx, true); err != nil {
    if strings.Contains(err.Error(), "init captcha token failed") {
        // shield/anti-bot: back off and retry once
        time.Sleep(5 * time.Second)
        err = d.ensureCaptchaToken(ctx, true)
    }
    if err != nil {
        return fmt.Errorf("captcha init rejected (possible anti-bot or outage): %w", err)
    }
}

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Related errors


AI-assisted analysis of AlistGo/alist@843d9dc814 (2026-08-15). Data as JSON: /api/errors/c4565f76872b5c73. Report an issue: GitHub.