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: 5
-
Configure the upstream to log every request and return:
-
Send 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 then
Negative 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.
Description
The
response-ratelimitingplugin continues forwarding requests upstream when the remaining quota becomes negative, even withblock_on_first_violation: true.Kong returns
429to the client, but only after the request has reached the upstream service. This allows upstream processing to continue after the quota is exhausted.Environment
localSteps to reproduce
Attach the plugin to a service with this configuration:
Configure 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
429before 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:
200,200,200429,429When usage lands exactly on the limit, early blocking works as expected.
Identified cause
The access-phase check in
kong/plugins/response-ratelimiting/access.luaonly handles exactly zero remaining quota:Negative remaining values bypass this check. Changing the comparison to
<= 0prevented 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_violationalready enabled, rather than the plugin's default behavior.