RocketChat/Rocket.Chat · error · Error

Not logged in

Error message

Not logged in

What it means

Thrown by useToggleReactionMutation when the current user id (useUserId()) is falsy at the moment the mutation function runs. The guard exists because chat.react requires an authenticated session; reacting before login would otherwise send an unauthenticated POST that fails opaquely on the server. Throwing early gives a clear client-side cause.

Source

Thrown at apps/meteor/client/components/message/content/reactions/useToggleReactionMutation.ts:20

import { useEndpoint, useUserId } from '@rocket.chat/ui-contexts';
import type { UseMutationOptions, UseMutationResult } from '@tanstack/react-query';
import { useMutation } from '@tanstack/react-query';

type UseToggleReactionMutationVariables = {
	mid: IMessage['_id'];
	reaction: string;
};

export const useToggleReactionMutation = (
	options?: Omit<UseMutationOptions<void, Error, UseToggleReactionMutationVariables>, 'mutationFn'>,
): UseMutationResult<void, Error, UseToggleReactionMutationVariables> => {
	const uid = useUserId();
	const reactToMessage = useEndpoint('POST', '/v1/chat.react');

	return useMutation({
		mutationFn: async ({ mid, reaction }) => {
			if (!uid) {
				throw new Error('Not logged in');
			}

			await reactToMessage({ messageId: mid, reaction });
		},

		...options,
	});
};

View on GitHub (pinned to f9d3ec372b)

Solutions

  1. Ensure the component using this hook is only rendered/interactive when a valid user session exists — gate the reaction UI behind a logged-in check.
  2. If the error appears unexpectedly, check that the login flow completed and Meteor.userId() is set before enabling reactions.
  3. In tests, seed the logged-in user (Meteor.userId) before triggering the mutation.
  4. Handle the error in the mutation's onError to silently re-prompt login instead of showing a raw toast.

Example fix

// before: button always enabled
<ReactionButton onClick={() => toggle.mutate({ mid, reaction })} />

// after: disable when not logged in
const uid = useUserId();
<ReactionButton disabled={!uid} onClick={() => toggle.mutate({ mid, reaction })} />
Defensive patterns

Strategy: validation

Validate before calling

const uid = useUserId();
if (!uid) { throw new Error('Login required'); }
// or gate the UI: <button disabled={!uid} />

Type guard

function isLoggedIn(uid: string | null | undefined): uid is string {
  return typeof uid === 'string' && uid.length > 0;
}

Try / catch

try {
  await toggle.mutateAsync({ mid, reaction });
} catch (e) {
  if ((e as Error).message === 'Not logged in') {
    redirectToLogin();
  }
}

Prevention

When it happens

Trigger: Calling mutate({ mid, reaction }) when the user is logged out, the account is in a logging-out transition, the session token was cleared, or useUserId returned undefined because the UserContext provider has no loaded user. Also reachable if the component rendering the reaction button outlives the session teardown.

Common situations: The user clicked a reaction button in the instant their session expired; a background tab resumed after the token expired; an automated/E2E test that did not establish a logged-in session before interacting; a race where the reaction mutation fires during logout.

Related errors


AI-assisted analysis of RocketChat/Rocket.Chat@f9d3ec372b (2026-08-12). Data as JSON: /api/errors/61f43d2940dd4a9c. Report an issue: GitHub.