RocketChat/Rocket.Chat · error · NotAuthorizedError

not-authorized

not-authorized

Error message

Not authorized

What it means

Thrown as NotAuthorizedError (error id 'not-authorized') in the useOpenRoom queryFn. It fires when the current user object exists but has no username (account incompletely provisioned), or when there is no user at all and the Accounts_AllowAnonymousRead setting is false. The query is marked non-retryable for this error in the retry function.

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 f9d3ec372b)

Solutions

  1. Ensure the logged-in user has a username set (admin > users, or via SET username flow) before opening rooms.
  2. If anonymous browsing is intended, enable Accounts_AllowAnonymousRead in server settings.
  3. Guard the route so it waits for the full user profile (including username) to load before invoking useOpenRoom.

Example fix

// before
if ((user && !user.username) || (!user && !allowAnonymousRead)) {
  throw new NotAuthorizedError();
}

// after: wait for user profile to settle, then decide
if (userLoading) return;
if ((user && !user.username) || (!user && !allowAnonymousRead)) {
  throw new NotAuthorizedError();
}
Defensive patterns

Strategy: validation

Validate before calling

// Ensure user is fully loaded with a username (or anonymous read allowed) before opening a room.
if (!userLoading && ((user && !user.username) || (!user && !allowAnonymousRead))) {
  // redirect to login or username-setup instead of running useOpenRoom
}

Type guard

const isFullyProvisionedUser = (u: unknown): u is { _id: string; username: string } =>
  typeof u === 'object' && u !== null &&
  typeof (u as any)._id === 'string' &&
  typeof (u as any).username === 'string' && (u as any).username.length > 0;

Try / catch

// NotAuthorizedError is unrecoverable; handle at the query error boundary.
if (error instanceof NotAuthorizedError) {
  return <NotAuthorizedScreen reason={error.details} />;
}

Prevention

When it happens

Trigger: Authenticated session where Meteor.user() is loaded but the username field is missing; anonymous access disabled (Accounts_AllowAnonymousRead=false) and the visitor has no user; route opened before the user document finished syncing the username field.

Common situations: Freshly created account before username was set; LDAP/SAML login that did not map a username; guest/anonymous browsing with anonymous read turned off in admin settings.

Related errors


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