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
- If you are the visitor: log in with a valid account that has a username.
- If anonymous access is intended, enable Accounts_SetAnonymousRead (Enterprise Edition) in workspace settings.
- If the account lacks a username, complete the user profile/username via the user settings or admin UI, then reload the room route.
- 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
- Gate room routes on an authenticated-with-username check before mounting the room view.
- If anonymous browsing is required, verify the Accounts_SetAnonymousRead EE setting is on.
- Complete username setup during account provisioning so no user lingers without one.
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
- 403
- [accounts] changeStorageBackend failed
- cannot-access-room
- error-action-not-allowed
- error-action-not-allowed
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)