Regression: new check_username rate limit can block normal signup flow

Since the recent change in PR #43042, /u/check_username.json is rate limited to 10 requests per minute per IP.

This appears to cause a regression in the normal signup flow.

While creating a new account, Discourse automatically checks username availability. A user does not need to submit the form repeatedly to hit this limit. Simply entering an email address and username, pausing while typing, changing the username, or correcting it can result in multiple requests to /u/check_username.json.

Once the limit is reached, the signup form displays:

You’ve performed this action too many times, please try again later.

The error is shown directly below the username field and effectively blocks the user from continuing until the rate limiter expires.

There is no indication how long the user should wait, and from the user’s perspective it looks like the chosen username or signup form is broken.

Steps to reproduce

  1. Open the signup form as an anonymous user.
  2. Enter a valid email address.
  3. Enter and modify the username several times, allowing the username availability check to run between changes.
  4. Continue until /u/check_username.json has been called more than 10 times within one minute.
  5. The username field starts showing the rate limiter error:
    You've performed this action too many times, please try again later.

Expected behaviour

A normal user completing or correcting the signup form should not be blocked by an internal rate limit triggered by automatic username availability checks.

If rate limiting is required for abuse prevention, the normal signup UX should degrade gracefully rather than expose a rate-limit error and prevent account creation.

Actual behaviour

The user receives an inline validation error on the username field and cannot continue normally until the rate limit expires.

Relevant change

This appears to have been introduced by:

PR #43042 – DEV: Rate limit check_username requests per IP

The current implementation uses:

RateLimiter.new(
  current_user,
  "check-username-#{request.remote_ip}",
  10,
  1.minute
).performed!

The signup UI itself can generate multiple username checks, so a limit of 10 requests per minute can be reached during legitimate interaction.

This may also even be more problematic for users behind shared NAT/public IP addresses, since the limiter is per IP rather than per session.

Additional observation

check_email also has a 10 requests/minute/IP limiter, but when that limit is exceeded it returns a successful response rather than surfacing the rate-limit error to the user.

It might therefore make sense for check_username to behave similarly, or alternatively:

  • increase the limit;

  • make it configurable;

  • avoid counting username suggestion/automatic validation requests in the same bucket;

  • or handle rate limiting client-side without blocking the signup flow.

    I can reproduce this on a current Discourse installation, including https://try.discourse.org/ after the change from PR #43042.

1 Like