# Diagnosing a misfiring @upstash/ratelimit
## Symptom A: legitimate users get 429s
- Check the algorithm. Fixed window counts hard resets at window
boundaries: two requests straddling the boundary both count fully.
Sliding window smooths this.
- Check the identifier. A constant identifier like "api" applies one
global limit to all users. One abusive client burns everyones
quota. Use per-user or per-IP identifiers.
- Check dynamic limits. If enabled, a stale dynamic limit override
can sit far below your intended rate. Read it back with
getDynamicLimit.
## Symptom B: abuse gets through
- Fixed window leaks bursts at boundaries by design. If bursts are
your threat, switch to sliding window or token bucket.
- The runtime cache only stores identifiers AFTER they were rate
limited once. On serverless cold starts the cache is empty, so the
first burst of every cold instance always hits Redis. That is a
latency cost, not a bypass: Redis still enforces.
- Multi-region without waitUntil on pending: regions diverge and each
enforces only its local view.
## Step 3: confirm with getRemaining
getRemaining(identifier) shows the current quota state without
consuming. Compare it against what you configured. If the numbers do
not match your config, the limiter instance in production differs
from the one you think you deployed.
## Fix and verify
Align algorithm, identifier granularity, and dynamic limits with the
threat. Then burst-test: send 2x the limit in a tight loop and
confirm roughly the expected fraction gets 429s.