RocketChat/Rocket.Chat · warning · Meteor.Error
error-too-many-requests
error-too-many-requests
Error message
Error, too many requests. Please slow down. You must wait ${timeToResetAttempsInSeconds} seconds before trying this endpoint again. What it means
Per-route REST rate limiting in ApiClass: for routes registered with a rate limiter, every call increments the counter and re-checks the allowance; when the check reports not allowed within the window, the request fails with error-too-many-requests carrying timeToReset/seconds in details, and X-RateLimit-Limit, X-RateLimit-Remaining and X-RateLimit-Reset headers are set on the response.
Source
Thrown at apps/meteor/server/api/ApiClass.ts:443
response: Response,
userId?: string,
): Promise<void> {
if (!(await this.shouldVerifyRateLimit(objectForRateLimitMatch.route, userId))) {
return;
}
rateLimiterDictionary[objectForRateLimitMatch.route].rateLimiter.increment(objectForRateLimitMatch);
const attemptResult = await rateLimiterDictionary[objectForRateLimitMatch.route].rateLimiter.check(objectForRateLimitMatch);
const timeToResetAttempsInSeconds = Math.ceil(attemptResult.timeToReset / 1000);
response.headers.set(
'X-RateLimit-Limit',
String(rateLimiterDictionary[objectForRateLimitMatch.route].options.numRequestsAllowed ?? ''),
);
response.headers.set('X-RateLimit-Remaining', String(attemptResult.numInvocationsLeft));
response.headers.set('X-RateLimit-Reset', String(new Date().getTime() + attemptResult.timeToReset));
if (!attemptResult.allowed) {
throw new Meteor.Error(
'error-too-many-requests',
`Error, too many requests. Please slow down. You must wait ${timeToResetAttempsInSeconds} seconds before trying this endpoint again.`,
{
timeToReset: attemptResult.timeToReset,
seconds: timeToResetAttempsInSeconds,
},
);
}
}
public registerRateLimiterForRoute({
route,
rateLimiterOptions = defaultRateLimiterOptions,
methods,
}: {
route: string;
rateLimiterOptions?: RateLimiterOptions;
methods: string[];View on GitHub (pinned to e4b8178b20)
Solutions
- Back off and retry after the X-RateLimit-Reset moment (or the seconds value in the error details).
- Reduce request frequency, batch with pagination (count/offset), or cache responses client-side.
- Server-side, tune the limits when the route is registered via registerRateLimiterForRoute (numRequestsAllowed / intervalTime) if the workload legitimately needs more.
Example fix
// before
setInterval(() => api.get('/v1/users.list'), 100); // bursts past the limit
// after — honor the reset window
const res = await api.get('/v1/users.list');
const resetAt = Number(res.headers.get('x-ratelimit-reset'));
const waitMs = Math.max(0, resetAt - Date.now()) + 100;
await new Promise((r) => setTimeout(r, waitMs)); Defensive patterns
Strategy: retry
Validate before calling
// adaptive throttle from response headers, before the next call
const remaining = Number(res.headers.get('x-ratelimit-remaining') ?? Infinity);
if (remaining <= 1) {
const resetAt = Number(res.headers.get('x-ratelimit-reset'));
await new Promise((r) => setTimeout(r, Math.max(0, resetAt - Date.now()) + 50));
} Try / catch
async function callWithBackoff<T>(fn: () => Promise<T>, maxRetries = 5): Promise<T> {
for (let attempt = 0; ; attempt++) {
try {
return await fn();
} catch (e: any) {
if (e?.error !== 'error-too-many-requests' || attempt >= maxRetries) throw e;
const wait = (e.details?.timeToReset as number) ?? 10_000;
await new Promise((r) => setTimeout(r, wait + Math.random() * 500)); // honor reset + jitter
}
}
} Prevention
- Read and honor X-RateLimit-Remaining/Reset headers on every response
- Batch list endpoints with count/offset instead of tight request loops
- Add jitter to scheduled jobs so many clients do not sync on the same interval
When it happens
Trigger: Exceeding numRequestsAllowed requests to the same rate-limited REST route within the configured interval from the same matched caller (per the route's objectForRateLimitMatch, typically IP/userId combination).
Common situations: Polling loops, import/export scripts, monitoring hitting endpoints too fast, many clients behind one NAT IP, deployment dashboards hammering list endpoints.
Understand the failure class
- HTTP status errors: handling 4xx and 5xx responses — how to handle 4xx and 5xx responses properly.
Related errors
- too-many-requests
- Room not found
- error-abac-attribute-store-external
- error-abac-not-enabled
- error-action-not-allowed
AI-assisted analysis of RocketChat/Rocket.Chat@e4b8178b20 (2026-08-18).
Data as JSON: /api/errors/1af2daa703ef8884.
Report an issue: GitHub.