{"record":{"id":"c5fcb55d6a08091f","repo":"coollabsio/coolify","slug":"too-many-messages-sent","errorCode":null,"errorMessage":"Too many messages sent!","messagePattern":"Too many messages sent!","errorType":"exception","errorClass":"Exception","httpStatus":null,"severity":"warning","filePath":"app/Livewire/Notifications/Email.php","lineNumber":352,"sourceCode":"            $this->validate([\n                'testEmailAddress' => 'required|email',\n            ], [\n                'testEmailAddress.required' => 'Test email address is required.',\n                'testEmailAddress.email' => 'Please enter a valid email address.',\n            ]);\n\n            $executed = RateLimiter::attempt(\n                'test-email:'.$this->team->id,\n                $perMinute = 0,\n                function () {\n                    $this->team?->notifyNow(new Test($this->testEmailAddress, 'email'));\n                    $this->dispatch('success', 'Test Email sent.');\n                },\n                $decaySeconds = 10,\n            );\n\n            if (! $executed) {\n                throw new \\Exception('Too many messages sent!');\n            }\n        } catch (\\Throwable $e) {\n            return handleError($e, $this);\n        }\n    }\n\n    public function copyFromInstanceSettings()\n    {\n        $this->authorize('update', $this->settings);\n        $settings = instanceSettings();\n        $this->smtpFromAddress = $settings->smtp_from_address;\n        $this->smtpFromName = $settings->smtp_from_name;\n\n        if ($settings->smtp_enabled) {\n            $this->smtpEnabled = true;\n            $this->resendEnabled = false;\n        }\n","sourceCodeStart":334,"sourceCodeEnd":370,"githubUrl":"https://github.com/coollabsio/coolify/blob/70b9acc42467278373e00de77abb40684e25b395/app/Livewire/Notifications/Email.php#L334-L370","documentation":"The 'send test email' action wraps the mail in RateLimiter::attempt keyed `test-email:<teamId>` with a 10-second decay. When the limiter refuses the attempt it returns false and this exception is thrown via handleError. Note the configured allowance is `$perMinute = 0`: zero attempts are permitted, so with this config the limiter blocks the callback outright - if test emails never send at all, this is why.","triggerScenarios":"Clicking 'Send test email' again inside the 10-second decay window; more precisely, with the shown `$perMinute = 0` the limiter refuses every call (0 >= 0 in tooManyAttempts), so each click after the limit semantics applies throws instead of sending.","commonSituations":"Impatient double-clicks on the test button; a misconfigured attempt count of 0 making the button fail deterministically; several team members testing notifications simultaneously.","solutions":["Wait out the 10-second decay window and click once","If the test email never sends at all, raise the allowance in app/Livewire/Notifications/Email.php to at least 1 (e.g. `$perMinute = 2`) - zero is not a valid 'allow' value for RateLimiter::attempt","If a stale limiter entry is suspected, clear the cache key `test-email:<teamId>` (redis/cache driver)"],"exampleFix":"// before\n$executed = RateLimiter::attempt(\n    'test-email:'.$this->team->id,\n    $perMinute = 0,\n    fn () => $this->team?->notifyNow(new Test($this->testEmailAddress, 'email')),\n    $decaySeconds = 10,\n);\n// after - allow 2 test mails per 10s window\n$executed = RateLimiter::attempt(\n    'test-email:'.$this->team->id,\n    $perMinute = 2,\n    fn () => $this->team?->notifyNow(new Test($this->testEmailAddress, 'email')),\n    $decaySeconds = 10,\n);","handlingStrategy":"retry","validationCode":"// surface remaining wait time instead of throwing\n$key = 'test-email:'.$this->team->id;\nif (RateLimiter::tooManyAttempts($key, $perMinute)) {\n    $seconds = RateLimiter::availableIn($key);\n    $this->dispatch('error', \"Retry in {$seconds}s.\");\n    return;\n}\nRateLimiter::hit($key, 10); // then send","typeGuard":null,"tryCatchPattern":"Catch \\Throwable with handleError as the component already does, and translate 'Too many messages sent!' into a countdown message; also verify the allowance passed to RateLimiter::attempt is >= 1, since 0 blocks every attempt.","preventionTips":["Disable the send button client-side for the decay window after each click","Never pass 0 as the attempt allowance - it refuses all attempts, not 'first one free'","Key the limiter per team (as shown) so one team's tests never block another's"],"tags":["livewire","email","rate-limit","notifications"],"backgroundTag":"rate-limit-exceeded","analyzedSha":"70b9acc42467278373e00de77abb40684e25b395","analyzedAt":"2026-08-17T01:41:01.313Z","schemaVersion":2},"datasetVersion":"2026-08-17T04:17:16.089Z"}