RocketChat/Rocket.Chat · error · Error
invalid banner
Error message
invalid banner
What it means
`BannerModule.viewClosed` (`banner-core` core app) throws `Error('invalid banner')` when the nested `payload.payload.view.viewId` is missing. The viewId identifies which banner record to dismiss via `Banner.dismiss(userId, bannerId)`, so a close event without it cannot be routed to a banner.
Source
Thrown at apps/meteor/server/modules/core-apps/banner.module.ts:20
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
- Send the banner's identifier as `payload: { view: { viewId } }` in the viewClosed payload.
- Fetch the active banner (e.g. via the banners API) and use its `viewId` when building the close interaction.
- For server-side dismissal without a UI surface, call `Banner.dismiss(userId, bannerId)` directly.
Example fix
// before
payload: { view: { id: bannerId }, triggerId }
// after
payload: { view: { viewId: bannerId }, triggerId } Defensive patterns
Strategy: validation
Validate before calling
if (!payload.payload?.view?.viewId) {
throw new Error('viewId is required to close a banner-core banner');
}
await bannerModule.viewClosed(payload); Type guard
const hasBannerViewId = (
payload: UiKitCoreAppViewClosedPayload,
): payload is UiKitCoreAppViewClosedPayload & { payload: { view: { viewId: string } } } =>
Boolean(payload.payload?.view?.viewId); Try / catch
try {
await bannerModule.viewClosed(payload);
} catch (error) {
if (error instanceof Error && error.message === 'invalid banner') {
// rebuild the payload with view.viewId and retry
}
} Prevention
- Use view.viewId (not view.id) for banner-core close payloads
- Derive the viewId from the banner that was actually rendered
- Add payload schema checks in tests that exercise banner dismissal
When it happens
Trigger: A `viewClosed` interaction for `banner-core` where `view` or `view.viewId` is undefined — e.g. a modal-close payload shape (which carries `view.id`) reused for a banner, or a manually constructed payload that omits the view.
Common situations: Frontend code or apps sending `view: { id }` instead of `view: { viewId }`; payloads stripped by a JSON round-trip or logger; test fixtures that only set triggerId.
Related errors
AI-assisted analysis of RocketChat/Rocket.Chat@b2c16d5842 (2026-08-18).
Data as JSON: /api/errors/dbfa65e8e4a6e8a5.
Report an issue: GitHub.