RocketChat/Rocket.Chat · error · Meteor.Error

error-not-invited

error-not-invited

Error message

User was not invited to this room ${subscription.status}

What it means

Meteor.Error('error-not-invited') thrown by performAcceptRoomInvite when subscription.status !== 'INVITED' or subscription.inviter is falsy. The accept flow only works on a still-pending invitation; anything else is rejected before the join callbacks run.

Source

Thrown at apps/meteor/server/lib/rooms/acceptRoomInvite.ts:26

import { callbacks } from '../callbacks';
import { notifyOnSubscriptionChangedById } from '../notifyListener';

/**
 * Accepts a room invite when triggered by internal events such as federation
 * or third-party callbacks. Performs the necessary database updates and triggers
 * safe callbacks, ensuring no propagation loops are created during external event
 * processing.
 */

// TODO this funcion is pretty much the same as the one in addUserToRoom.ts, we should probably
// unify them at some point
export const performAcceptRoomInvite = async (
	room: IRoom,
	subscription: ISubscription,
	user: IUser & { username: string },
): Promise<void> => {
	if (subscription.status !== 'INVITED' || !subscription.inviter) {
		throw new Meteor.Error('error-not-invited', `User was not invited to this room ${subscription.status}`);
	}
	const inviter = await Users.findOneById(subscription.inviter._id);

	await callbacks.run('beforeJoinRoom', user, room);

	await callbacks.run('beforeAddedToRoom', { user, inviter }, room);

	try {
		await Apps.self?.triggerEvent(AppEvents.IPreRoomUserJoined, room, user, inviter);
	} catch (error: any) {
		if (error.name === AppsEngineException.name) {
			throw new Meteor.Error('error-app-prevented', error.message);
		}

		throw error;
	}

	await Subscriptions.acceptInvitationById(subscription._id);

View on GitHub (pinned to b2c16d5842)

Solutions

  1. Refetch the subscription and only offer 'accept' while status === 'INVITED' and inviter exists.
  2. Treat the error as idempotency feedback: refresh the room list and continue without alarming the user.
  3. Repair subscriptions missing inviter metadata if produced by an import.

Example fix

// before
await performAcceptRoomInvite(room, subscription, user); // throws error-not-invited

// after
if (subscription.status === 'INVITED' && subscription.inviter) {
  await performAcceptRoomInvite(room, subscription, user);
}
Defensive patterns

Strategy: validation

Validate before calling

const sub = await Subscriptions.findOneByRoomIdAndUserId(room._id, user._id, { projection: { status: 1, inviter: 1 } });
if (sub?.status === 'INVITED' && sub.inviter) {
  await performAcceptRoomInvite(room, sub, user as IUser & { username: string });
} else {
  // not a pending invite: refresh state instead of accepting
}

Type guard

const isPendingInvite = (
  s: ISubscription | null | undefined,
): s is ISubscription & { status: 'INVITED'; inviter: NonNullable<ISubscription['inviter']> } =>
  !!s && s.status === 'INVITED' && !!s.inviter;

Try / catch

try {
  await performAcceptRoomInvite(room, subscription, user);
} catch (error: any) {
  if (error?.error === 'error-not-invited') {
    // already accepted/declined: refresh the room list and continue
  }
}

Prevention

When it happens

Trigger: Calling acceptRoomInvite for an invitation that was already accepted or declined, whose subscription was superseded (kick/re-invite), or whose inviter metadata is missing.

Common situations: User double-clicks Accept; two tabs accept the same invite; stale invite links/emails; imported subscriptions without inviter data.

Related errors


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