RocketChat/Rocket.Chat · error · Error

invalid user

Error message

invalid user

What it means

`CloudSubscriptionCommunication` (appId `cloud-communication-core`, extends `CloudAnnouncementsModule`) handles cloud subscription/communication modals. Its `viewClosed()` override requires `payload.user._id` to attribute the close; when missing it throws a plain `Error('invalid user')` before notifying Cloud.

Source

Thrown at apps/meteor/server/modules/core-apps/cloudSubscriptionCommunication.module.ts:16

import type { UiKitCoreAppViewClosedPayload } from '@rocket.chat/core-services';
import type * as UiKit from '@rocket.chat/ui-kit';

import { CloudAnnouncementsModule } from './cloudAnnouncements.module';

export class CloudSubscriptionCommunication extends CloudAnnouncementsModule {
	override appId = 'cloud-communication-core';

	override async viewClosed(payload: UiKitCoreAppViewClosedPayload): Promise<UiKit.ServerInteraction> {
		const {
			payload: { view: { viewId } = {} },
			user: { _id: userId } = {},
		} = payload;

		if (!userId) {
			throw new Error('invalid user');
		}

		if (!viewId) {
			throw new Error('invalid view');
		}

		if (!payload.triggerId) {
			throw new Error('invalid triggerId');
		}

		// for viewClosed we just need to let Cloud know that the banner was closed, no need to wait for the response

		void this.handlePayload(payload);

		return {
			type: 'modal.close',
			triggerId: payload.triggerId,
			appId: payload.appId,

View on GitHub (pinned to b2c16d5842)

Solutions

  1. Include `user: { _id: userId }` in the viewClosed payload.
  2. If acting server-side, avoid the module and dismiss via `Banner.dismiss` or the appropriate service directly.
  3. Ensure the dispatcher always attaches the acting user to core-app interactions.

Example fix

// before
await cloudCommunicationModule.viewClosed({ appId: 'cloud-communication-core', payload: { view: { viewId } }, triggerId } as any);

// after
await cloudCommunicationModule.viewClosed({ appId: 'cloud-communication-core', user: { _id: userId }, payload: { view: { viewId } }, triggerId } as any);
Defensive patterns

Strategy: validation

Validate before calling

const canClose = (payload: UiKitCoreAppViewClosedPayload): boolean =>
  Boolean(payload.user?._id && payload.payload?.view?.viewId && payload.triggerId);

if (canClose(payload)) {
  await cloudCommunicationModule.viewClosed(payload);
}

Type guard

function isCompleteCloudCommunicationClosePayload(
  payload: UiKitCoreAppViewClosedPayload,
): payload is UiKitCoreAppViewClosedPayload & { user: { _id: string }; payload: { view: { viewId: string } }; triggerId: string } {
  return Boolean(payload.user?._id && payload.payload?.view?.viewId && payload.triggerId);
}

Try / catch

try {
  await cloudCommunicationModule.viewClosed(payload);
} catch (error) {
  if (error instanceof Error && error.message === 'invalid user') {
    return; // no user to attribute the close to
  }
  throw error;
}

Prevention

When it happens

Trigger: A `viewClosed` interaction for `cloud-communication-core` where `payload.user` or `payload.user._id` is undefined — synthetic payloads, test doubles, or a session that lost its user context.

Common situations: Programmatic closing of cloud subscription modals; mocks omitting the user; stale surfaces after logout.

Related errors


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