RocketChat/Rocket.Chat · error · Meteor.Error
tag-not-found
tag-not-found
Error message
Tag not found
What it means
removeTag loads the livechat tag by id before deleting and running the livechat.afterTagRemoved callback. If no tag matches the id, it throws tag-not-found for method livechat:removeTag.
Solutions
- Refresh the tags list and only delete ids that still appear
- Make delete flows idempotent: treat tag-not-found as success when the goal is absence
- Verify the id via the tag list endpoint before deleting
Defensive patterns
Strategy: try-catch
Validate before calling
const tag = await LivechatTag.findOneById(_id, { projection: { _id: 1 } });
if (!tag) {
// already removed; nothing to do
}
await LivechatEnterprise.removeTag(_id); Try / catch
try {
await LivechatEnterprise.removeTag(_id);
} catch (err) {
if ((err as Meteor.Error)?.error === 'tag-not-found') {
// treat as success: the tag is gone
} else {
throw err;
}
} Prevention
- Make tag deletion idempotent in UI and scripts
- Refresh the tag list after concurrent edits
- Disable the delete button while a deletion is in flight
When it happens
Trigger: Calling livechat:removeTag with a deleted or never-existing tag id; double-delete from concurrent UI actions.
Common situations: Two admins deleting the same tag; stale tag list after removal; automation re-running a delete step.
Understand the failure class
Background: 'Could not be found', 'does not exist', 'not found in database': the resource-not-found family when an ID, slug, key, or URI lookup comes back empty — this error's family across 20 libraries.
Related errors
- department-not-found
- error-canned-response-not-found
- error-canned-response-not-found
- error-contact-not-found
- error-contact-not-found
AI-assisted analysis of RocketChat/Rocket.Chat@b2c16d5842 (2026-08-18).
Data as JSON: /api/errors/4f0d37620721e002.
Report an issue: GitHub.
Appendix: source
Thrown at apps/meteor/ee/server/lib/omnichannel/LivechatEnterprise.ts:137
const validUserMonitors = await Users.findUsersInRolesWithQuery(
'livechat-monitor',
{ _id: { $in: unitMonitors.map(({ monitorId }) => monitorId) } },
{ projection: { _id: 1, username: 1 } },
).toArray();
const monitors = validUserMonitors.map(({ _id: monitorId, username }) => ({
monitorId,
username: username!,
}));
return LivechatUnit.createOrUpdateUnit(_id, unitData, ancestors, monitors, unitDepartments);
},
async removeTag(_id: string) {
const tag = await LivechatTag.findOneById<Pick<ILivechatTag, '_id' | 'name'>>(_id, { projection: { _id: 1, name: 1 } });
if (!tag) {
throw new Meteor.Error('tag-not-found', 'Tag not found', { method: 'livechat:removeTag' });
}
await callbacks.run('livechat.afterTagRemoved', tag);
return LivechatTag.removeById(_id);
},
async saveTag(_id: string | undefined, tagData: { name: string; description?: string }, tagDepartments: string[] | undefined) {
return LivechatTag.createOrUpdateTag(_id, tagData, tagDepartments);
},
async saveSLA(
_id: string | null,
slaData: Pick<IOmnichannelServiceLevelAgreements, 'name' | 'description' | 'dueTimeInMinutes'>,
executedBy: string,
) {
const oldSLA =
_id &&
(await OmnichannelServiceLevelAgreements.findOneById<Pick<IOmnichannelServiceLevelAgreements, 'dueTimeInMinutes'>>(_id, {View on GitHub (pinned to b2c16d5842)