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
- 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.
- If the error appears unexpectedly, check that the login flow completed and Meteor.userId() is set before enabling reactions.
- In tests, seed the logged-in user (Meteor.userId) before triggering the mutation.
- 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
- Disable reaction controls when useUserId() is falsy.
- Do not render interactive message actions during logout transitions.
- Seed a logged-in user in E2E tests before triggering reactions.
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.