RocketChat/Rocket.Chat · error · Error

error-invalid-user

error-invalid-user

Error message

error-invalid-user

What it means

Thrown by the POST ldap.syncNow endpoint when this.userId is falsy. Because the route declares authRequired:true, the framework middleware should have rejected the request with 401 before the handler runs; reaching this throw indicates the auth context was lost or the route middleware was bypassed. It is effectively a defensive guard against a missing user session. Code is the raw string 'error-invalid-user' (plain Error, not Meteor.Error).

Source

Thrown at apps/meteor/ee/server/api/ldap.ts:32

	required: ['message', 'success'],
	additionalProperties: false,
});

API.v1.post(
	'ldap.syncNow',
	{
		authRequired: true,
		forceTwoFactorAuthenticationForNonEnterprise: true,
		twoFactorRequired: true,
		response: {
			200: ldapSyncNowResponseSchema,
			400: validateBadRequestErrorResponse,
			401: validateUnauthorizedErrorResponse,
		},
	},
	async function action() {
		if (!this.userId) {
			throw new Error('error-invalid-user');
		}

		if (!(await hasPermissionAsync(this.user, 'sync-auth-services-users'))) {
			throw new Error('error-not-authorized');
		}

		if (settings.get('LDAP_Enable') !== true) {
			throw new Error('LDAP_disabled');
		}

		await LDAPEnterprise.sync();
		await LDAPEnterprise.syncAvatarAndAbacAttributes();

		return API.v1.success({
			message: 'Sync_in_progress' as const,
		});
	},
);

View on GitHub (pinned to f9d3ec372b)

Solutions

  1. Authenticate the request: send a valid X-Auth-Token + X-User-Id header (or resume token) so the framework populates this.userId.
  2. If testing, seed this.userId on the request context before invoking the action.
  3. Audit any custom middleware on the ldap.syncNow route that could clear this.user.
  4. Confirm the API framework version correctly runs authRequired before the action.

Example fix

// before (test): handler invoked with no user context
await action.call({});

// after: seed userId on the bound context
await action.call({ userId: 'rocketchat.internal.admin.test', user: adminUser });
Defensive patterns

Strategy: validation

Validate before calling

// Ensure auth context is present before invoking the handler (e.g. in tests)
function assertUserId(ctx: { userId?: string }): asserts ctx is { userId: string } {
  if (!ctx.userId) throw new Error('error-invalid-user');
}
assertUserId(this);

Type guard

function hasUserId(ctx: unknown): ctx is { userId: string; user: unknown } {
  return typeof ctx === 'object' && ctx !== null && typeof (ctx as any).userId === 'string';
}

Try / catch

try {
  await api.post('ldap.syncNow', {});
} catch (e) {
  if (e.message === 'error-invalid-user') {
    // re-authenticate, then retry once
    await relogin();
    return api.post('ldap.syncNow', {});
  }
  throw e;
}

Prevention

When it happens

Trigger: Calling POST /v1/ldap.syncNow with a missing/invalid auth token that somehow passed the authRequired gate, or invoking the action function outside the normal API middleware pipeline (e.g. direct unit test without seeding this.userId).

Common situations: Token expired between auth middleware and handler in a long-lived request; test harness calling the handler directly without mocking this.userId; custom middleware that strips the user object.

Related errors


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