RocketChat/Rocket.Chat · error · Error
invalid user
Error message
invalid user
What it means
`BannerModule` is the UiKit core app `banner-core` that processes close events for in-app banners. `viewClosed()` destructures `payload.user._id`; when it is missing there is no user to dismiss the banner for, so the module throws a plain `Error('invalid user')` before ever reaching `Banner.dismiss(userId, bannerId)`. This is a payload-shape guard, not an authentication check.
Source
Thrown at apps/meteor/server/modules/core-apps/banner.module.ts:16
import { Banner } from '@rocket.chat/core-services';
import type { IUiKitCoreApp, UiKitCoreAppViewClosedPayload } from '@rocket.chat/core-services';
import type * as UiKit from '@rocket.chat/ui-kit';
export class BannerModule implements IUiKitCoreApp {
appId = 'banner-core';
// when banner view is closed we need to dismiss that banner for that user
async viewClosed(payload: UiKitCoreAppViewClosedPayload): Promise<UiKit.ServerInteraction> {
const {
payload: { view: { viewId: bannerId } = {} },
user: { _id: userId } = {},
} = payload;
if (!userId) {
throw new Error('invalid user');
}
if (!bannerId) {
throw new Error('invalid banner');
}
if (!payload.triggerId) {
throw new Error('invalid triggerId');
}
await Banner.dismiss(userId, bannerId);
return {
type: 'banner.close',
triggerId: payload.triggerId,
appId: payload.appId,
viewId: bannerId,
};View on GitHub (pinned to b2c16d5842)
Solutions
- Include `user: { _id: userId }` in the `viewClosed` payload.
- For programmatic dismissal, bypass the module and call `Banner.dismiss(userId, bannerId)` from `@rocket.chat/core-services` directly.
- Make sure the code path that generates the `triggerId` also attaches the acting user to the interaction payload.
Example fix
// before
await bannerModule.viewClosed({
appId: 'banner-core',
payload: { view: { viewId: bannerId }, triggerId },
} as any);
// after
await bannerModule.viewClosed({
appId: 'banner-core',
user: { _id: userId },
payload: { view: { viewId: bannerId }, triggerId },
} as any); Defensive patterns
Strategy: validation
Validate before calling
const canDismiss = (payload: UiKitCoreAppViewClosedPayload): boolean =>
Boolean(payload.user?._id && payload.payload?.view?.viewId && payload.triggerId);
if (canDismiss(payload)) {
await bannerModule.viewClosed(payload);
} Type guard
function isCompleteBannerClosePayload(
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 bannerModule.viewClosed(payload);
} catch (error) {
if (error instanceof Error && error.message === 'invalid user') {
return; // no user context: nothing to dismiss
}
throw error;
} Prevention
- Always attach the acting user when building UiKit core interactions
- Call Banner.dismiss directly for programmatic banner dismissal
- Type payloads with UiKitCoreAppViewClosedPayload instead of casting to any
When it happens
Trigger: Dispatching a `viewClosed` interaction to the `banner-core` app where `payload.user` or `payload.user._id` is undefined — e.g. a programmatically built payload, a test double that omits the user, or a client still rendering a banner after logout.
Common situations: Custom server code closing banners by emitting UiKit core events instead of calling `Banner.dismiss`; payload mocks in unit tests; DDP reconnect after logout while a banner surface is still open.
Related errors
AI-assisted analysis of RocketChat/Rocket.Chat@b2c16d5842 (2026-08-18).
Data as JSON: /api/errors/7e18bf55445329f6.
Report an issue: GitHub.