Skip to content

[13.x] Fix Redis throttle returning a timestamp as the remaining attempts - #61748

Merged
taylorotwell merged 2 commits into
laravel:13.xfrom
sumaiazaman:13.x-fix-redis-throttle-remaining-header
Sep 28, 2026
Merged

taylorotwell merged 2 commits into
laravel:13.xfrom
sumaiazaman:13.x-fix-redis-throttle-remaining-header

Conversation

@sumaiazaman

Copy link
Copy Markdown
Contributor

When using throttleWithRedis() with a limit that only counts some responses, the first request of a window returns a Unix timestamp as the remaining attempts:

RateLimiter::for('api', fn () => Limit::perMinute(5)->after(fn ($response) => $response->status() === 404));
X-RateLimit-Limit: 5
X-RateLimit-Remaining: 1790494157

DurationLimiter::tooManyAttempts() reads the Lua result as [decaysAt, remaining], but when the key doesn't exist or the window has expired the script returns {0, now + decay}, the other way around. Without after() this is hidden because hit() runs straight away and overwrites both values, but when the response isn't counted the header is built from the swapped values. The cache based ThrottleRequests middleware returns 5 here.

This returns the decay time and the max attempts in the right order, using tonumber() so remaining is an integer like in the other branches. The existing DurationLimiterTest assertion that expected the timestamp placeholder is updated to match.

@taylorotwell
taylorotwell merged commit 5086cce into laravel:13.x Sep 28, 2026
62 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants