RocketChat/Rocket.Chat · error · Error
invalid triggerId
Error message
invalid triggerId
What it means
`CloudAnnouncementsModule.viewClosed` throws `Error('invalid triggerId')` when `payload.triggerId` is falsy. The triggerId is needed both to acknowledge the close to Cloud (the interaction is forwarded via `handlePayload`) and to address the `banner.close`/`modal.close` response back to the client surface, so the guard fires before dismissal.
Source
Thrown at apps/meteor/server/modules/core-apps/cloudAnnouncements.module.ts:67
return this.handlePayload(payload);
}
async viewClosed(payload: UiKitCoreAppViewClosedPayload): Promise<UiKit.ServerInteraction | undefined> {
const {
payload: { view: { viewId, id } = {} },
user: { _id: userId } = {},
} = payload;
if (!userId) {
throw new Error('invalid user');
}
if (!id && !viewId) {
throw new Error('invalid view');
}
if (!payload.triggerId) {
throw new Error('invalid triggerId');
}
// For backwards compatibility: we prefer to use viewId, but some legacy banners
// may only have id. We fetch all matching banners and prioritize viewId match.
const bannerIds = [viewId, id].filter((bannerId) => isTruthy(bannerId));
const banners = await Banners.findByIds(bannerIds).toArray();
const announcement = banners.find((b) => b._id === viewId) || banners.find((b) => b._id === id);
if (!announcement) {
throw new Error('Banner not found');
}
await Banner.dismiss(userId, announcement._id);
const type = announcement.surface === 'banner' ? 'banner.close' : 'modal.close';
// 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);View on GitHub (pinned to b2c16d5842)
Solutions
- Forward the `triggerId` from the surface that displayed the announcement in the viewClosed payload.
- For dismissal without a UI surface, call `Banner.dismiss(userId, bannerId)` directly — no triggerId needed.
Example fix
// before
await module.viewClosed({ appId: 'cloud-announcements-core', user: { _id: userId }, payload: { view: { viewId } } } as any);
// after
await module.viewClosed({ appId: 'cloud-announcements-core', user: { _id: userId }, payload: { view: { viewId } }, triggerId } as any); Defensive patterns
Strategy: validation
Validate before calling
if (!payload.triggerId) {
throw new Error('triggerId is required to close a cloud announcement');
}
await announcementsModule.viewClosed(payload); Type guard
const hasTrigger = (
payload: UiKitCoreAppViewClosedPayload,
): payload is UiKitCoreAppViewClosedPayload & { triggerId: string } =>
typeof payload.triggerId === 'string' && payload.triggerId.length > 0; Try / catch
try {
await announcementsModule.viewClosed(payload);
} catch (error) {
if (error instanceof Error && error.message === 'invalid triggerId') {
// fall back to Banner.dismiss(userId, bannerId) without notifying the surface
}
} Prevention
- Propagate triggerId from the surface that displayed the announcement
- Call Banner.dismiss directly when no client response is needed
When it happens
Trigger: Closing a cloud announcement banner via a viewClosed interaction that carries no `triggerId` — e.g. manually constructed payloads, replayed log entries, or an outdated client that does not propagate the trigger.
Common situations: Custom scripts mimicking the banner close flow; test doubles omitting trigger metadata; intermediate layers dropping fields.
Related errors
- invalid user
- invalid view
- Invalid user data received from Rocket.Chat Cloud
- invalid triggerId
- invalid triggerId
AI-assisted analysis of RocketChat/Rocket.Chat@b2c16d5842 (2026-08-18).
Data as JSON: /api/errors/41b87c0818466495.
Report an issue: GitHub.