RocketChat/Rocket.Chat · error · Meteor.Error

error-user-registration-secret

error-user-registration-secret

Error message

User registration is only allowed via Secret URL

What it means

Thrown by 'registerUser' when Accounts_RegistrationForm is 'Secret URL' and the client sent no secretURL at all. In Secret URL mode the payload must carry formData.secretURL matching the configured Accounts_RegistrationForm_SecretURL, or a valid invite token. The method fails fast on the missing parameter before touching invite validation.

Source

Thrown at apps/meteor/server/meteor-methods/users/registerUser.ts:82

			pass: String,
			name: String,
			secretURL: Match.Optional(String),
			reason: Match.Optional(String),
		}),
	);

	if (settings.get('Accounts_RegistrationForm') === 'Disabled') {
		throw new Meteor.Error('error-user-registration-disabled', 'User registration is disabled', {
			method: 'registerUser',
		});
	}

	if (
		settings.get('Accounts_RegistrationForm') === 'Secret URL' &&
		(!formData.secretURL || formData.secretURL !== settings.get('Accounts_RegistrationForm_SecretURL'))
	) {
		if (!formData.secretURL) {
			throw new Meteor.Error('error-user-registration-secret', 'User registration is only allowed via Secret URL', {
				method: 'registerUser',
			});
		}

		try {
			await validateInviteToken(formData.secretURL);
		} catch (e) {
			throw new Meteor.Error('error-user-registration-secret', 'User registration is only allowed via Secret URL', {
				method: 'registerUser',
			});
		}
	}

	passwordPolicy.validate(formData.pass);

	await validateEmailDomain(formData.email);

	const userData = {

View on GitHub (pinned to b2c16d5842)

Solutions

  1. Include formData.secretURL: either the value of Accounts_RegistrationForm_SecretURL or the token from the invite URL (/invite/:token or /register/:hash).
  2. If users should register without an invite: switch Registration Form to 'Public' in Administration > Accounts.
  3. If you are the admin: copy the exact Secret URL/invite link and distribute that link to users.

Example fix

// before
await Meteor.callAsync('registerUser', { email, pass, name });

// after: forward the token from the invite URL the user arrived on
const token = FlowRouter.getParam('hash'); // e.g. /register/:hash
await Meteor.callAsync('registerUser', { email, pass, name, secretURL: token });
Defensive patterns

Strategy: validation

Validate before calling

const secretURL = new URLSearchParams(location.search).get('invite')
  ?? FlowRouter.getParam('hash');
if (!secretURL) {
  showError('Registration requires an invitation link.');
} else {
  await Meteor.callAsync('registerUser', { ...formData, secretURL });
}

Try / catch

try {
  await Meteor.callAsync('registerUser', { ...formData, secretURL });
} catch (e) {
  if ((e as Meteor.Error).error === 'error-user-registration-secret') {
    showError('Open the invitation link sent to you, then register from that page.');
  }
}

Prevention

When it happens

Trigger: Meteor.callAsync('registerUser', { email, pass, name }) with no secretURL field while Registration Form = 'Secret URL'; a custom signup form that did not forward the token from the invite link; navigating directly to /register instead of the invite URL.

Common situations: Custom signup UIs that hardcode the plain form while the workspace admin switched to Secret URL mode; invite links where the hash query param was stripped by a redirect or email client.

Related errors


AI-assisted analysis of RocketChat/Rocket.Chat@b2c16d5842 (2026-08-18). Data as JSON: /api/errors/397f04a7e287ca81. Report an issue: GitHub.