RocketChat/Rocket.Chat · error · Meteor.Error

error-unit-not-found

error-unit-not-found

Error message

Unit not found

What it means

saveUnit, when updating (non-null _id), loads the unit with findOneById scoped by the caller's allowed units to read its ancestors. If no unit matches, it throws error-unit-not-found for method livechat:saveUnit.

Solutions

  1. Reload the unit from the server before saving and confirm it still exists
  2. Ensure the saving user has access to the unit, or save from an unrestricted admin
  3. If the unit was deleted, create it anew instead of saving the stale id
Defensive patterns

Strategy: validation

Validate before calling

const unit = _id && (await LivechatUnit.findOneById(_id, { projection: { _id: 1 } }));
if (_id && !unit) {
	// unit no longer editable: reload the form or create a new unit
}
await LivechatEnterprise.saveUnit(_id, unitData, unitMonitors, unitDepartments, userId);

Try / catch

try {
	await LivechatEnterprise.saveUnit(_id, unitData, unitMonitors, unitDepartments, userId);
} catch (err) {
	if ((err as Meteor.Error)?.error === 'error-unit-not-found') {
		// reload units; save only when the target still exists in the caller's scope
	} else {
		throw err;
	}
}

Prevention

When it happens

Trigger: Saving an edit to a unit whose id no longer exists or is outside the caller's unit scope (getUnitsFromUser).

Common situations: Editing a unit deleted in another session; stale form after unit re-organization; unit-scoped admin editing an out-of-scope unit.

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


AI-assisted analysis of RocketChat/Rocket.Chat@b2c16d5842 (2026-08-18). Data as JSON: /api/errors/25e317b901d4e30f. Report an issue: GitHub.

Appendix: source

Thrown at apps/meteor/ee/server/lib/omnichannel/LivechatEnterprise.ts:111

		check(unitDepartments, [
			Match.ObjectIncluding({
				departmentId: String,
			}),
		]);

		let ancestors: string[] = [];
		if (_id) {
			const unitsFromUser = await getUnitsFromUser(userId);
			const unit = await LivechatUnit.findOneById<Pick<IOmnichannelBusinessUnit, '_id' | 'ancestors'>>(
				_id,
				{
					projection: { _id: 1, ancestors: 1 },
				},
				{ unitsFromUser },
			);
			if (!unit) {
				throw new Meteor.Error('error-unit-not-found', 'Unit not found', {
					method: 'livechat:saveUnit',
				});
			}

			ancestors = unit.ancestors || [];
		}

		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!,
		}));

View on GitHub (pinned to b2c16d5842)