RocketChat/Rocket.Chat · error · Error
invalid user
Error message
invalid user
What it means
`CloudAnnouncementsModule` (appId `cloud-announcements-core`) handles Rocket.Chat Cloud announcement banners. Its `viewClosed()` dismisses the announcement for the acting user and notifies Cloud, so it requires `payload.user._id`; when missing it throws a plain `Error('invalid user')` before any dismissal or Cloud call happens.
Source
Thrown at apps/meteor/server/modules/core-apps/cloudAnnouncements.module.ts:59
return settings.get('Cloud_Url');
}
blockAction(payload: UiKitCoreAppBlockActionPayload): Promise<UiKit.ServerInteraction | undefined> {
return this.handlePayload(payload);
}
viewSubmit(payload: UiKitCoreAppViewSubmitPayload): Promise<UiKit.ServerInteraction | undefined> {
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');
}View on GitHub (pinned to b2c16d5842)
Solutions
- Include `user: { _id: userId }` in the viewClosed payload.
- For programmatic dismissal, call `Banner.dismiss(userId, bannerId)` from `@rocket.chat/core-services` directly instead of going through the module.
- Verify the dispatcher (uiKit core app bus) attaches the current user to every interaction it forwards.
Example fix
// before
await announcementsModule.viewClosed({
appId: 'cloud-announcements-core',
payload: { view: { viewId: bannerId }, triggerId },
} as any);
// after
await announcementsModule.viewClosed({
appId: 'cloud-announcements-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.payload?.view?.id) && payload.triggerId);
if (canDismiss(payload)) {
await announcementsModule.viewClosed(payload);
} Type guard
function isCompleteAnnouncementClosePayload(
payload: UiKitCoreAppViewClosedPayload,
): payload is UiKitCoreAppViewClosedPayload & { user: { _id: string }; triggerId: string } {
return Boolean(payload.user?._id && payload.triggerId);
} Try / catch
try {
await announcementsModule.viewClosed(payload);
} catch (error) {
if (error instanceof Error && error.message === 'invalid user') {
return; // cannot attribute the dismissal to a user
}
throw error;
} Prevention
- Attach user._id to every core-app interaction payload
- Use Banner.dismiss for programmatic dismissal of cloud announcements
- Cover payload shape in unit tests of interaction handlers
When it happens
Trigger: A `viewClosed` interaction for a cloud announcement banner where `payload.user` / `payload.user._id` is undefined — e.g. a synthetic payload from custom code, or an interaction dispatched after the user's session context was lost.
Common situations: Custom automation that closes announcement banners by dispatching UiKit events; test payloads built without the user field; stale clients after logout or session expiry.
Related errors
- invalid view
- invalid triggerId
- Invalid user data received from Rocket.Chat Cloud
- invalid user
- invalid user
AI-assisted analysis of RocketChat/Rocket.Chat@b2c16d5842 (2026-08-18).
Data as JSON: /api/errors/ea9a56644fa03710.
Report an issue: GitHub.