Response Rate Limiting forwards requests upstream after quota is exceeded with block_on_first_violation enabled
Description
The response-ratelimiting plugin continues forwarding requests upstream when the remaining quota becomes negative, even with block_on_first_violation: true.
Kong returns 429 to the client, but only after the request has reached the upstream service. This allows upstream processing to continue after the quota is exhausted.
Environment
- Kong OSS: 3.9.3
- Kubernetes: v1.30.0, running on Minikube
- Deployment: DB-less, one Kong pod with two Nginx workers
- Counter policy:
local
Steps to reproduce
Attach the plugin to a service with this configuration:
name: response-ratelimiting config: header_name: X-Kong-Limit block_on_first_violation: true fault_tolerant: false limit_by: ip policy: local limits: requests: hour: 5Configure the upstream to log every request and return:
X-Kong-Limit: requests=2Send three sequential requests from the same client, allowing response accounting to complete between requests. These consume six units against the five-unit quota, leaving a remaining quota of
-1.Send two additional requests and inspect both their responses and the upstream logs.
Expected behavior
Once the stored usage reaches or exceeds the quota, Kong should reject subsequent requests with 429 before forwarding them upstream.
Requests already in flight are outside the scope of this issue.
Actual behavior
The additional requests return 429, but both still reach the upstream.
Observed during testing:
| Requests | Client responses | Upstream requests |
|---|---|---|
| First three | 200, 200, 200 |
3 |
| Next two | 429, 429 |
2 |
When usage lands exactly on the limit, early blocking works as expected.
Identified cause
The access-phase check in kong/plugins/response-ratelimiting/access.lua only handles exactly zero remaining quota:
if conf.block_on_first_violation and lv.remaining == 0 thenNegative remaining values bypass this check. Changing the comparison to <= 0 prevented subsequent over-limit requests from reaching upstream in the same Minikube reproduction.
Related discussion
Related to #1096. This report specifically concerns negative remaining quota with block_on_first_violation already enabled, rather than the plugin's default behavior.
Source: Kong/kong