RocketChat/Rocket.Chat · warning · Error

error-e2e-key-reset-in-progress

Error message

error-e2e-key-reset-in-progress

What it means

Thrown by POST e2e.resetRoomKey when a key reset is already running for the same room: the endpoint guards concurrent resets with an in-module Map (LockMap) keyed by rid and throws new Error('error-e2e-key-reset-in-progress') if LockMap.has(rid). It is a per-process, in-memory lock, so it applies to concurrent calls on the same server instance and is released in a finally block when the reset finishes or fails.

Solutions

  1. Wait for the in-flight reset to finish (they are bounded by room size) and re-issue the request once.
  2. Debounce the reset button / serialize resets per room in the client so only one request is in flight.
  3. If the error persists long after any plausible reset duration, restart the Meteor server to clear a wedged LockMap entry.

Example fix

// before
await api.post('e2e.resetRoomKey', body); // user can double-fire

// after — one reset per room at a time, retry on in-progress
const inFlight = new Set();
async function resetRoomKey(rid, body) {
  if (inFlight.has(rid)) return;
  inFlight.add(rid);
  try { await api.post('e2e.resetRoomKey', body); }
  finally { inFlight.delete(rid); }
}
Defensive patterns

Strategy: retry

Try / catch

for (let attempt = 1; attempt <= 5; attempt++) {
  try { await api.post('e2e.resetRoomKey', body); break; }
  catch (e) {
    if (e.message !== 'error-e2e-key-reset-in-progress' || attempt === 5) throw e;
    await delay(attempt * 1000); // prior reset still running for this rid
  }
}

Prevention

When it happens

Trigger: Two POST /api/v1/e2e.resetRoomKey requests for the same rid overlapping in time — e.g. a client retrying a slow reset, double-click on 'Reset key', or two sessions of the same user resetting simultaneously.

Common situations: Impatient users re-clicking during a long reset on a big room; frontend retry logic with a too-short timeout; parallel key-rotation scripts hitting the same room. Note a stuck lock (see the not-allowed path that throws after LockMap.set without cleanup) keeps producing this error until the server restarts.

Related errors


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

Appendix: source

Thrown at apps/meteor/server/api/v1/e2e.ts:445

			authRequired: true,
			body: isE2EResetRoomKeyProps,
			response: {
				400: validateBadRequestErrorResponse,
				401: validateUnauthorizedErrorResponse,
				403: validateForbiddenErrorResponse,
				200: ajv.compile<void>({
					type: 'object',
				}),
			},
		},

		async function action() {
			const { rid, e2eKey, e2eKeyId } = this.bodyParams;
			if (!(await hasPermissionAsync(this.user, 'toggle-room-e2e-encryption', rid))) {
				return API.v1.forbidden('error-not-allowed');
			}
			if (LockMap.has(rid)) {
				throw new Error('error-e2e-key-reset-in-progress');
			}

			LockMap.set(rid, true);

			if (!(await canAccessRoomIdAsync(rid, this.userId))) {
				throw new Error('error-not-allowed');
			}

			try {
				await resetRoomKey(rid, this.userId, e2eKey, e2eKeyId);
				return API.v1.success();
			} catch (e) {
				console.error(e);
				return API.v1.failure('error-e2e-key-reset-failed');
			} finally {
				LockMap.delete(rid);
			}
		},

View on GitHub (pinned to b2c16d5842)