symfony/http-kernel · error · InvalidArgumentException

Rate limiter " " does not exist. Did you forget to…

Error message

Rate limiter "%s" does not exist. Did you forget to configure it? Available limiters: "%s".

What it means

RateLimitAttributeListener resolves the limiter named by the #[RateLimit] attribute from a container locator. If the named limiter service does not exist, an InvalidArgumentException is thrown listing the limiters that ARE configured.

Solutions

  1. Define the limiter in config: framework.rate_limiter.<name> with a factory policy matching the attribute's limiter value.
  2. Correct the limiter name in #[RateLimit(limiter: ...)] to match an available limiter (see the exception's list).
  3. Run config:dump-reference / debug:rate-limiter (if available) to verify registered limiter names.

Example fix

// before
#[RateLimit(limiter: 'api')]
// after (with config: framework: rate_limiter: { basic: ... })
#[RateLimit(limiter: 'basic')]
Defensive patterns

Strategy: validation

Validate before calling

$available = array_keys($limiters->getProvidedServices());
if (!in_array($limiterName, $available, true)) { throw new \InvalidArgumentException("Unknown limiter '$limiterName'"); }

Try / catch

try { $listener->onKernelControllerAttribute($event, 'kernel.controller', ...); } catch (\InvalidArgumentException $e) { /* surface misconfigured limiter name with the available list from the message */ }

Prevention

When it happens

Trigger: A controller annotated with #[RateLimit(limiter: 'foo')] where no limiter named 'foo' is registered (e.g. missing limiter config under framework.rate_limiter, or a typo in the limiter name), during onKernelControllerAttribute.

Common situations: Symfony config defining limiters under a different key than the attribute; forgetting symfony/rate-limiter configuration entirely; renaming a limiter without updating attributes; typo between YAML key and attribute value.

Understand the failure class

Background: 'Could not be found', 'does not exist', 'not found in database': the resource-not-found family when an ID, slug, key, or URI lookup comes back empty — this error's family across 20 libraries.

Related errors


AI-assisted analysis of symfony/http-kernel@aa3a39d728 (2026-09-13). Data as JSON: /api/errors/41871ca77a3775a8. Report an issue: GitHub.

Appendix: source

Thrown at EventListener/RateLimitAttributeListener.php:57

    public function __construct(
        private readonly ServiceProviderInterface $limiters,
    ) {
    }

    /**
     * @param ControllerAttributeEvent<RateLimit, ControllerArgumentsEvent> $event
     */
    public function onKernelControllerAttribute(ControllerAttributeEvent $event, ?string $eventName = null, ?EventDispatcherInterface $dispatcher = null): void
    {
        $request = $event->kernelEvent->getRequest();
        $attribute = $event->attribute;

        if ($attribute->methods && !\in_array($request->getMethod(), $attribute->methods, true)) {
            return;
        }

        if (!$this->limiters->has($attribute->limiter)) {
            throw new \InvalidArgumentException(\sprintf('Rate limiter "%s" does not exist. Did you forget to configure it? Available limiters: "%s".', $attribute->limiter, implode('", "', array_keys($this->limiters->getProvidedServices()))));
        }

        if (null === $attribute->key) {
            $key = ($request->getClientIp() ?? 'unknown').'~'.$request->getMethod().'~'.$request->getPathInfo();
        } elseif (!\is_string($key = $event->evaluate($attribute->key))) {
            throw new \TypeError(\sprintf('The value of the "$key" option of the "%s" attribute must evaluate to a string, "%s" given.', RateLimit::class, get_debug_type($key)));
        }

        $rateLimit = $this->limiters->get($attribute->limiter)->create($key)->consume($attribute->tokens);

        $candidate = $attribute->exposeHeaders && null !== $rateLimit->getResetAt()
            ? new AppliedRateLimit($rateLimit, $attribute->tokens)
            : null;

        if (!$rateLimit->isAccepted()) {
            $request->attributes->set(self::RATE_LIMIT_ATTRIBUTE, $candidate);

            if ($dispatcher && class_exists(RateLimitExceededEvent::class)) {

View on GitHub (pinned to aa3a39d728)