{"record":{"id":"8f48a2754e3955ce","repo":"RocketChat/Rocket.Chat","slug":"banner-not-found-8f48a2","errorCode":null,"errorMessage":"Banner not found","messagePattern":"Banner not found","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"warning","filePath":"apps/meteor/server/services/banner/service.ts","lineNumber":95,"sourceCode":"\t\t\t\t\t// such as the seatsTaken banner. In this case, we use the bannerId as the viewId\n\t\t\t\t\tviewId: banner.view.viewId || banner._id,\n\t\t\t\t},\n\t\t\t\t// add surface to legacy banners\n\t\t\t\tsurface: !banner.surface ? 'banner' : banner.surface,\n\t\t\t}));\n\t}\n\n\tasync dismiss(userId: string, bannerId: string): Promise<boolean> {\n\t\tif (!userId || !bannerId) {\n\t\t\tthrow new Error('Invalid params');\n\t\t}\n\n\t\tconst banner = await Banners.findOneById(bannerId);\n\t\tif (!banner) {\n\t\t\tconst { matchedCount } = await Users.setBannerReadById(userId, bannerId);\n\n\t\t\tif (!matchedCount) {\n\t\t\t\tthrow new Error('Banner not found');\n\t\t\t}\n\n\t\t\tvoid notifyOnUserChange({\n\t\t\t\tid: userId,\n\t\t\t\tclientAction: 'updated',\n\t\t\t\tdiff: {\n\t\t\t\t\t[`banners.${bannerId}.read`]: true,\n\t\t\t\t},\n\t\t\t});\n\n\t\t\treturn true;\n\t\t}\n\n\t\tconst user = await Users.findOneById<Pick<IUser, 'username' | '_id'>>(userId, {\n\t\t\tprojection: { username: 1 },\n\t\t});\n\t\tif (!user) {\n\t\t\tthrow new Error('User not found');","sourceCodeStart":77,"sourceCodeEnd":113,"githubUrl":"https://github.com/RocketChat/Rocket.Chat/blob/b2c16d5842cbe6b69b59bdf6fc5e5f1afcd1f0b0/apps/meteor/server/services/banner/service.ts#L77-L113","documentation":"Thrown by the banner service's dismiss() when the bannerId does not exist in the Banners collection AND the user has no banners.<bannerId>.read record. The method first tries the banner document; if absent it treats the id as an already-read legacy per-user banner and updates Users.setBannerReadById — when that matches nothing either, there is no banner to dismiss and it throws.","triggerScenarios":"dismiss(userId, 'stale-id') after the banner was deleted from the database; client retries dismissal with an id never issued; typos in bannerId.","commonSituations":"Race between a user closing a banner and an admin removing it; multiple tabs retrying dismiss after the first succeeded but the user record was reset; imports that drop banner documents but keep client-side state.","solutions":["Treat 'Banner not found' as success (idempotent dismiss) in the caller","Confirm the bannerId comes from a current Banners.findOneById query or the banner payload the client received","Avoid re-dismissing after the first success"],"exampleFix":"// before\nawait bannerService.dismiss(userId, bannerId);\n\n// after\ntry {\n  await bannerService.dismiss(userId, bannerId);\n} catch (e) {\n  if (e.message !== 'Banner not found') throw e;\n}","handlingStrategy":"try-catch","validationCode":"const banner = await Banners.findOneById(bannerId);\nconst userReadIt = Boolean(await Users.findOneByIdAndBannerRead(userId, bannerId));\nif (!banner && !userReadIt) { /* treat as already dismissed, skip the call */ }","typeGuard":null,"tryCatchPattern":"try { await bannerService.dismiss(userId, bannerId); } catch (e) { if (e.message === 'Banner not found') { return true; /* idempotent success */ } throw e; }","preventionTips":["Track dismissed banner ids client-side to avoid repeat dismiss calls","Treat dismissal as idempotent because banners can vanish at any time"],"tags":["banner","not-found","idempotency","rocket-chat"],"backgroundTag":"resource-not-found","analyzedSha":"b2c16d5842cbe6b69b59bdf6fc5e5f1afcd1f0b0","analyzedAt":"2026-08-18T15:26:39.429Z","contentChangedAt":"2026-08-18T15:26:39.429Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}