RocketChat/Rocket.Chat · error · Meteor.Error

error-unauthorized

error-unauthorized

Error message

Users must have a username

What it means

Thrown by the Hono authentication middleware when a user object is resolved by authenticatedRoute() but the user has no username field (isUserWithUsername returns false). This blocks authenticated-but-usernameless accounts from accessing routes that don't explicitly set userWithoutUsername: true. The check runs after auth/anonymous gating, so the user identity is known — it is the username that is missing.

Source

Thrown at apps/meteor/server/api/v1/middlewares/authenticationHono.ts:42

		const user = await api.authenticatedRoute(convertHonoContextToApiActionContext(c, { logger: options.logger }));
		const shouldPreventAnonymousRead = !user && options.authOrAnonRequired && !settings.get('Accounts_AllowAnonymousRead');
		const shouldPreventUserRead = !user && options.authRequired;

		if (shouldPreventAnonymousRead || shouldPreventUserRead) {
			const result = api.unauthorized('You must be logged in to do this.');
			// TODO: MAJOR
			if (!applyBreakingChanges) {
				Object.assign(result.body, {
					status: 'error',
					message: 'You must be logged in to do this.',
				});
			}

			return c.json(result.body, result.statusCode);
		}

		if (user && !options.userWithoutUsername && !isUserWithUsername(user)) {
			throw new Meteor.Error('error-unauthorized', 'Users must have a username');
		}

		c.set('user', user);
		return next();
	};
}

View on GitHub (pinned to f9d3ec372b)

Solutions

  1. Ensure the user account has a username assigned — via admin user management or the user completing their profile setup.
  2. If the endpoint legitimately serves users without usernames (e.g., method.call routes that already set userWithoutUsername: true), add userWithoutUsername: true to the route's options.
  3. For OAuth/SAML users, ensure the username mapping is configured in the OAuth/SAML settings.

Example fix

// before (route definition without the flag)
API.v1.get('my-endpoint', { authRequired: true }, action);
// after (allow usernameless users if the endpoint supports it)
API.v1.get('my-endpoint', { authRequired: true, userWithoutUsername: true }, action);
Defensive patterns

Strategy: type-guard

Type guard

// Type guard to verify a user object has a username before making API calls
import type { IUser } from '@rocket.chat/core-typings';

function userHasUsername(user: IUser | null | undefined): user is IUser & { username: string } {
  return !!user && typeof user.username === 'string' && user.username.length > 0;
}

// Usage before calling an endpoint that requires a username
if (!userHasUsername(currentUser)) {
  console.warn('Current user has no username — this endpoint will reject the request.');
}

Try / catch

try {
  await callApiEndpoint();
} catch (e) {
  if (e.error === 'error-unauthorized' && e.reason?.includes('username')) {
    console.error('User account has no username. Complete profile setup or contact admin.');
    return;
  }
  throw e;
}

Prevention

When it happens

Trigger: An authenticated request where the user account exists and is valid but the username property is undefined. This can happen with certain OAuth/SAML accounts that did not complete username assignment, bot accounts created without a username, or users in a partially-migrated state.

Common situations: OAuth provider (Google, GitHub, etc.) returned no username and the account registration flow was interrupted; a bot or integration token was created programmatically without setting username; data migration from another platform left some users without usernames; the username was set to null by a cleanup script.

Related errors


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