RocketChat/Rocket.Chat · error · NotAuthorizedError

not-authorized

not-authorized

Error message

Not authorized

What it means

NotAuthorizedError (error id `not-authorized`) thrown inside the useOpenRoom react-query queryFn before any server call. It fires when the current user is logged in but has no username, or when there is no logged-in user and anonymous read is disabled for the workspace. It signals that the caller is not permitted to resolve/open a room by name at all.

Solutions

  1. If you are the visitor: log in with a valid account that has a username.
  2. If anonymous access is intended, enable Accounts_SetAnonymousRead (Enterprise Edition) in workspace settings.
  3. If the account lacks a username, complete the user profile/username via the user settings or admin UI, then reload the room route.
  4. In app code, gate room routes on a logged-in-with-username check and redirect to home/login instead of letting useOpenRoom throw.

Example fix

// before
const { data } = useOpenRoom(type, reference); // throws not-authorized for anonymous

// after
const user = useUserId();
const username = useUserDisplayName(); // resolves only when username set
if (!user && !anonymousReadEnabled) {
	return <NotAuthorizedPage />;
}
const { data } = useOpenRoom(type, reference);
Defensive patterns

Strategy: validation

Validate before calling

const canOpenRoom = (user: { username?: string } | null, allowAnonymousRead: boolean): boolean =>
	Boolean(user?.username) || (!user && allowAnonymousRead);

Type guard

const isNotAuthorizedError = (error: unknown): error is RocketChatError<'not-authorized'> =>
	Boolean(error && typeof error === 'object' && 'error' in error && (error as { error: string }).error === 'not-authorized');

Try / catch

try {
	const { rid } = await openRoomQueryFn();
} catch (error) {
	if (isNotAuthorizedError(error)) {
		redirect('/home'); // not retriable: fix auth state instead
		return;
	}
	throw error;
}

Prevention

When it happens

Trigger: Opening a room route while logged in as an account whose username is not yet set (e.g. user creation flow incomplete), or an anonymous visitor hitting /channel/:name when the Accounts_SetAnonymousRead setting is false (EE).

Common situations: Anonymous read toggle turned off after links were shared publicly; a half-provisioned bot/ghost account without a username; tests that render room routes without a fully seeded user.

Understand the failure class

Background: Permission denied / not authorized / 403 Forbidden: access-control rejections when the caller lacks the required role, grant, or ownership — this error's family across 18 libraries.

Related errors


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

Appendix: source

Thrown at apps/meteor/client/views/room/hooks/useOpenRoom.ts:70

		return { rid: sub.rid };
	}, [reference, type, user?._id]);

	const result = useQuery({
		// we need to add uid and username here because `user` is not loaded all at once (see UserProvider -> Meteor.user())
		queryKey: roomsQueryKeys.roomReference(reference, type, user?._id, user?.username),

		// Render immediately from local cache when we already know the rid; queryFn still runs in
		// the background to revalidate permissions / fetch fresh room fields.
		placeholderData: tryCacheShortcut,

		queryFn: async (): Promise<{ rid: IRoom['_id'] }> => {
			const cached = tryCacheShortcut();
			if (cached) {
				LegacyRoomManager.open({ typeName: type + reference, rid: cached.rid });
				return cached;
			}
			if ((user && !user.username) || (!user && !allowAnonymousRead)) {
				throw new NotAuthorizedError();
			}

			if (!reference || !type) {
				throw new RoomNotFoundError(undefined, { type, reference });
			}

			let roomData: IRoom;
			try {
				roomData = await getRoomByTypeAndName(type, reference);
			} catch (error) {
				const errorCode = error && typeof error === 'object' && 'error' in error ? error.error : undefined;

				// "No permission" means the room exists but the user can't see it — surface the
				// not-found/no-access screen rather than retrying it as a transient failure.
				if (errorCode === 'error-no-permission') {
					throw new RoomNotFoundError(undefined, { type, reference });
				}

View on GitHub (pinned to 2f18297792)