RocketChat/Rocket.Chat · error · Meteor.Error

invalid-department

invalid-department

Error message

Provided department does not exists

What it means

Thrown by `setDepartmentForGuest({ visitorId, department })` when `LivechatDepartment.findOneById(department, { projection: { _id: 1 } })` returns null. Before switching a visitor to a new department (LivechatVisitors.updateDepartmentById), the target department must exist.

Source

Thrown at apps/meteor/server/lib/omnichannel/departmentsLib.ts:204

) {
	const department = await LivechatDepartment.findOneById<Pick<ILivechatDepartment, 'enabled'>>(_id, { projection: { enabled: 1 } });
	if (!department) {
		throw new Meteor.Error('error-department-not-found', 'Department not found');
	}

	return updateDepartmentAgents(_id, departmentAgents, department.enabled);
}

export async function setDepartmentForGuest({ visitorId, department }: { visitorId: string; department: string }) {
	livechatLogger.debug({
		msg: 'Switching departments for visitor',
		visitorId,
		department,
	});

	const dep = await LivechatDepartment.findOneById<Pick<ILivechatDepartment, '_id'>>(department, { projection: { _id: 1 } });
	if (!dep) {
		throw new Meteor.Error('invalid-department', 'Provided department does not exists');
	}

	// Visitor is already validated at this point
	return LivechatVisitors.updateDepartmentById(visitorId, department);
}

export async function removeDepartment(departmentId: string) {
	livechatLogger.debug({ msg: 'Removing department', departmentId });

	const department = await LivechatDepartment.findOneById<Pick<ILivechatDepartment, '_id' | 'businessHourId' | 'parentId'>>(departmentId, {
		projection: { _id: 1, businessHourId: 1, parentId: 1 },
	});
	if (!department) {
		throw new Error('error-department-not-found');
	}

	const { _id } = department;

View on GitHub (pinned to b2c16d5842)

Solutions

  1. Fetch the current department list (`GET /v1/livechat/department`) and use a valid id before assigning
  2. Make widget department configuration dynamic instead of hard-coded
  3. If the department was deleted, pick a fallback existing department or omit department to use routing defaults

Example fix

// before
await setDepartmentForGuest({ visitorId, department: 'dep-gone' });

// after
const dep = await LivechatDepartment.findOneByIdOrName('sales', { projection: { _id: 1 } });
if (!dep) throw new Error('Configure a valid department for the widget');
await setDepartmentForGuest({ visitorId, department: dep._id });
Defensive patterns

Strategy: validation

Validate before calling

const dep = await LivechatDepartment.findOneByIdOrName(department, { projection: { _id: 1 } });
if (!dep) throw new Error('Invalid department configured');
await setDepartmentForGuest({ visitorId, department: dep._id });

Type guard

const isValidDepartment = async (idOrName: string): Promise<boolean> =>
  (await LivechatDepartment.findOneByIdOrName(idOrName, { projection: { _id: 1 } })) != null;

Try / catch

try {
  await setDepartmentForGuest({ visitorId, department });
} catch (e) {
  if (isMeteorError(e, 'invalid-department')) {
    // fall back to default routing (omit department)
  }
}

Prevention

When it happens

Trigger: Livechat widget/API flows that assign a department to a visitor using an id or name slug that no longer resolves — e.g. a widget still embedding a department deleted after deployment, or a department selector defaulting to a stale value.

Common situations: Widget snippets hard-coding a department; departments renamed/recreated (new _id) while clients cache the old one; preview environments pointing at prod department ids.

Understand the failure class

Background: "Not found" and "does not exist" errors: why "Task not found", "No such folder", and "Can't find" fire when a lookup comes back empty — this error's family across 14 libraries.

Related errors


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