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

  1. Back off and retry after the X-RateLimit-Reset moment (or the seconds value in the error details).
  2. Reduce request frequency, batch with pagination (count/offset), or cache responses client-side.
  3. 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

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

Related errors


AI-assisted analysis of RocketChat/Rocket.Chat@e4b8178b20 (2026-08-18). Data as JSON: /api/errors/1af2daa703ef8884. Report an issue: GitHub.