@upstash/ratelimit
semver
>=1.0.0postconditions11functions8last verified2026-06-24coverage score89%Postconditions: what we check
- limit · ratelimit-limit-no-try-catcherrorWhenNetwork failure to Redis OR invalid Upstash credentials — Redis HTTP call throws when the connection fails before the timeout logic resolves.Throws
Error (network failure or auth error from @upstash/redis HTTP client)Required handlingCaller MUST wrap ratelimit.limit() in try-catch. If Redis is unreachable, the underlying HTTP client throws. In most serverless API routes, this unhandled error crashes the entire request. Fail open (return true/allow) on Redis errors to avoid blocking all users when the rate limiter is unavailable.costmediumin prodimmediate exceptionusers seeservice unavailablevisibilityvisible - blockUntilReady · ratelimit-blockuntilready-no-try-catcherrorWhentimeout parameter is <= 0 OR underlying Redis network failure throws Error before blockUntilReady can resolveThrows
Error('timeout must be positive') | Error (network failure from Redis)Required handlingCaller MUST wrap ratelimit.blockUntilReady() in try-catch. The method throws synchronously if timeout <= 0, and can propagate Redis network errors.costmediumin prodimmediate exceptionusers seeservice unavailablevisibilityvisibleSources[1] - resetUsedTokens · ratelimit-resetusedtokens-no-try-catcherrorWhenUnderlying Redis HTTP call fails due to network failure or auth error. Unlike limit(), resetUsedTokens() does NOT have a timeout/fail-open mechanism — it will always propagate the Redis error to the caller.Throws
Error (network failure or auth error from @upstash/redis HTTP client)Required handlingCaller MUST wrap ratelimit.resetUsedTokens() in try-catch. Unlike limit(), there is no built-in timeout/fail-open for this method. A Redis failure during an admin reset operation will throw and crash the calling request handler.costlowin prodimmediate exceptionusers seeservice unavailablevisibilityvisible - getRemaining · ratelimit-getremaining-no-try-catcherrorWhenUnderlying Redis HTTP call fails due to network failure or auth error. getRemaining() has no timeout or fail-open mechanism — it propagates all Redis errors to the caller.Throws
Error (network failure or auth error from @upstash/redis HTTP client)Required handlingCaller MUST wrap ratelimit.getRemaining() in try-catch. Used in response headers (X-RateLimit-Remaining) or dashboard endpoints — an unhandled Redis error here crashes the API response. Fail gracefully by returning cached or default values when Redis is unreachable.costlowin prodimmediate exceptionusers seedegraded performancevisibilityvisible - setDynamicLimit · ratelimit-setdynamiclimit-not-enablederrorWhenCalled when dynamicLimits was NOT set to true in the Ratelimit constructor. Throws synchronously before any Redis call is made.Throws
Error('dynamicLimits must be enabled in the Ratelimit constructor to use setDynamicLimit()')Required handlingCaller MUST wrap setDynamicLimit() in try-catch when dynamicLimits enablement is not guaranteed at the call site. This is a configuration error that indicates a code bug — the constructor option must be set to use this method.costlowin prodimmediate exceptionusers seeservice unavailablevisibilityvisible - setDynamicLimit · ratelimit-setdynamiclimit-redis-failureerrorWhendynamicLimits is enabled but the underlying Redis SET or DEL call fails due to network failure or auth error.Throws
Error (network failure from @upstash/redis HTTP client)Required handlingCaller MUST wrap setDynamicLimit() in try-catch. A failure to set a dynamic limit means the override was NOT applied — the rate limiter will continue using the old limit. This is especially dangerous in incident response scenarios where operators use setDynamicLimit() to throttle load.costmediumin prodimmediate exceptionusers seedegraded performancevisibilityvisibleSources[3] - getDynamicLimit · ratelimit-getdynamiclimit-not-enablederrorWhenCalled when dynamicLimits was NOT set to true in the Ratelimit constructor. Throws synchronously, identical pattern to setDynamicLimit.Throws
Error('dynamicLimits must be enabled in the Ratelimit constructor to use getDynamicLimit()')Required handlingCaller MUST wrap getDynamicLimit() in try-catch when dynamicLimits enablement is not guaranteed. This is a code configuration error.costlowin prodimmediate exceptionusers seeservice unavailablevisibilityvisibleSources[3] - getDynamicLimit · ratelimit-getdynamiclimit-redis-failureerrorWhendynamicLimits is enabled but the Redis GET call fails due to network failure or auth error.Throws
Error (network failure from @upstash/redis HTTP client)Required handlingCaller MUST wrap getDynamicLimit() in try-catch. Typically called in admin/monitoring endpoints — an uncaught error crashes the admin API.costlowin prodimmediate exceptionusers seedegraded performancevisibilityvisibleSources[3] - updateIpDenyList · ratelimit-updateipdenylist-threshold-errorerrorWhenthreshold parameter is not an integer between 1 and 8 (inclusive). ThresholdError is thrown synchronously before any network call.Throws
ThresholdError('Allowed threshold values are from 1 to 8, 1 and 8 included. Received: <n>')Required handlingCaller MUST wrap updateIpDenyList() in try-catch and handle ThresholdError separately for clear error messaging. Pass a value from 1 to 8 where lower values include more (less certain) IPs and higher values are more conservative.costlowin prodimmediate exceptionusers seedegraded performancevisibilityvisibleSources[4] - updateIpDenyList · ratelimit-updateipdenylist-network-failureerrorWhenExternal HTTP fetch to https://raw.githubusercontent.com/stamparm/ipsum/master/levels fails (GitHub unreachable, DNS failure, non-200 response). The error is wrapped in Error('Failed to fetch ip deny list: ...').Throws
Error('Failed to fetch ip deny list: <original error>')Required handlingCaller MUST wrap updateIpDenyList() in try-catch. This function makes an external HTTP call to GitHub, not Upstash — it can fail independently of Redis availability. Run in a background job with retry logic rather than in a hot request path.costlowin prodimmediate exceptionusers seedegraded performancevisibilitysilentSources[4] - disableIpDenyList · ratelimit-disableipdenylist-redis-failureerrorWhenRedis multi-command transaction (SDIFFSTORE, DEL, SET) fails due to network failure or auth error. The deny list is NOT disabled if this throws.Throws
Error (network failure from @upstash/redis HTTP client)Required handlingCaller MUST wrap disableIpDenyList() in try-catch. A failure here means the IP deny list remains active — requests from blocked IPs continue to be rejected. Used in emergency scenarios (false positives blocking legitimate users) so uncaught failure is operationally dangerous.costmediumin prodimmediate exceptionusers seedegraded performancevisibilityvisibleSources[4]
Sources
Every postcondition cites at least one of these. Grouped by source type; numbered to match the footnotes above.
Source code
- [1]raw.githubusercontent.com/upstash/ratelimit-js/mainupstash/ratelimit-js · ratelimit.ts
- [4]raw.githubusercontent.com/upstash/ratelimit-js/mainupstash/ratelimit-js · ip-deny-list.ts
Research notes
Curator notes from SOURCES.md captured when the profile was written so you can verify the reasoning, not just the rules.
Sources — @upstash/ratelimit
All URLs fetched on 2026-04-02.
Package Metadata
- https://www.npmjs.com/package/@upstash/ratelimit — npm page, version 2.0.8
- https://github.com/upstash/ratelimit-js — GitHub repository
Documentation
- https://upstash.com/docs/redis/sdks/ratelimit-ts/overview — Overview and quick start
- https://upstash.com/docs/redis/sdks/ratelimit-ts/features — Timeout and caching features
Source Code (fetched directly)
- https://raw.githubusercontent.com/upstash/ratelimit-js/main/src/ratelimit.ts — Main class, limit() and blockUntilReady() implementations
- https://raw.githubusercontent.com/upstash/ratelimit-js/main/src/types.ts — RatelimitResponse, RatelimitConfig types
Key Findings
TimeoutErrorclass is exported butlimit()does NOT throw it — timeout resolves with{ success: true, reason: "timeout" }- Underlying
@upstash/redisHTTP calls CAN throw (network, 401 auth errors) - Real-world usage pattern: calling
limit()without try-catch is common (roomGPT, lagon) - No known CVEs as of 2026-04-02 (checked socket.dev, aikido.dev)
Need a different package?
Request a profile