RocketChat/Rocket.Chat · error · Error

invalid-user

Error message

invalid-user

What it means

Inside findMentionedMessages (chat.getMentionedMessages flow), after room access passes, the helper loads the authenticated user by uid with a username projection to search for mentions of that username. If no user document exists for the uid on the request (Users.findOneById returns null) it throws plain Error 'invalid-user'. In practice this only happens when the auth token references a user that has since been deleted or the token is corrupt yet passed authentication.

Source

Thrown at apps/meteor/server/api/lib/messages.ts:27

	roomId,
	pagination: { offset, count, sort },
}: {
	uid: string;
	roomId: string;
	pagination: { offset: number; count: number; sort: FindOptions<IMessage>['sort'] };
}): Promise<{
	messages: IMessage[];
	count: number;
	offset: number;
	total: number;
}> {
	const room = await Rooms.findOneById(roomId);
	if (!room || !(await canAccessRoomAsync(room, { _id: uid }))) {
		throw new Error('error-not-allowed');
	}
	const user = await Users.findOneById<Pick<IUser, 'username'>>(uid, { projection: { username: 1 } });
	if (!user) {
		throw new Error('invalid-user');
	}

	const { cursor, totalCount } = Messages.findPaginatedVisibleByMentionAndRoomId(user.username, roomId, {
		sort: sort || { ts: -1 },
		skip: offset,
		limit: count,
	});

	const [messages, total] = await Promise.all([cursor.toArray(), totalCount]);

	return {
		messages,
		count: messages.length,
		offset,
		total,
	};
}

View on GitHub (pinned to b2c16d5842)

Solutions

  1. Re-authenticate: obtain a fresh token for a user that exists (check with GET /api/v1/me)
  2. If the account was deleted, recreate it or switch the integration to a service account
  3. For flaky occurrences, inspect whether a concurrent deletion is running

Example fix

// before
GET /api/v1/chat.getMentionedMessages  (X-Auth-Token of deleted user) -> invalid-user

// after
POST /api/v1/login { "user": "live.bot", "password": "..." }  // fresh token, then retry
Defensive patterns

Strategy: try-catch

Validate before calling

async function assertTokenAlive(client) {
  const me = await client.get('/api/v1/me');
  if (me.status === 401) throw new Error('token stale — re-authenticate');
}

Try / catch

try {
  await client.get('/api/v1/chat.getMentionedMessages', { params: { roomId } });
} catch (e: any) {
  if ((e?.response?.data?.error ?? '') === 'invalid-user') {
    // authed uid no longer exists: drop cached token, re-login once, then retry
    await invalidateTokenAndReauth();
  }
  throw e;
}

Prevention

When it happens

Trigger: Calling chat.getMentionedMessages with a token for a user deleted between token issuance and this request, or a hand-crafted/expired session whose userId no longer resolves.

Common situations: Long-lived bot/personal access token kept after the account was removed; user deleted mid-session while a client retried; workspace data restored from a backup that lacks the user row.

Related errors


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