RocketChat/Rocket.Chat · error · Meteor.Error
error-invalid-department
error-invalid-department
Error message
Invalid department
What it means
Thrown by the saveCannedResponse method when a canned response is saved with scope === 'department' but no departmentId value is supplied. Rocket.Chat requires a department-scoped canned response to be tied to a concrete LivechatDepartment record, so a missing departmentId is treated as invalid input rather than defaulted. This fires before any DB lookup of the department.
Source
Thrown at apps/meteor/ee/server/meteor-methods/saveCannedResponse.ts:67
// to avoid inconsistencies
if (responseData.scope === 'user') {
delete responseData.departmentId;
}
// TODO: check if the department i'm trying to save is a department i can interact with
// check if the response already exists and we're not updating one
const duplicateShortcut = await CannedResponse.findOneByShortcut(responseData.shortcut, {
projection: { _id: 1 },
});
if ((!_id && duplicateShortcut) || (_id && duplicateShortcut && duplicateShortcut._id !== _id)) {
throw new Meteor.Error('error-invalid-shortcut', 'Shortcut provided already exists', {
method: 'saveCannedResponse',
});
}
if (responseData.scope === 'department' && !responseData.departmentId) {
throw new Meteor.Error('error-invalid-department', 'Invalid department', {
method: 'saveCannedResponse',
});
}
if (
responseData.departmentId &&
!(await LivechatDepartment.findOneById<Pick<ILivechatDepartment, '_id'>>(responseData.departmentId, { projection: { _id: 1 } }))
) {
throw new Meteor.Error('error-invalid-department', 'Invalid department', {
method: 'saveCannedResponse',
});
}
let result: Omit<IOmnichannelCannedResponse, '_updatedAt' | '_createdAt'> & { _createdAt?: Date };
if (_id) {
const cannedResponse = await CannedResponse.findOneById(_id);
if (!cannedResponse) {View on GitHub (pinned to f9d3ec372b)
Solutions
- When scope === 'department', always send a non-empty departmentId alongside the request.
- If the caller does not have a department, set scope to 'user' or 'global' instead of 'department'.
- In the form layer, make the department field required (and re-enabled) whenever the scope selector equals 'department'.
- Unit-test the save path with scope:'department' and an empty departmentId to fail fast at the API boundary.
Example fix
// before
await saveCannedResponse(userId, { shortcut: 'hi', text: 'Hello', scope: 'department' });
// after
await saveCannedResponse(userId, { shortcut: 'hi', text: 'Hello', scope: 'department', departmentId }); Defensive patterns
Strategy: validation
Validate before calling
function validateCannedResponseInput(data: { scope: string; departmentId?: string }): string | null {
if (data.scope === 'department' && !data.departmentId) {
return 'A departmentId is required when scope is "department".';
}
return null;
}
// const err = validateCannedResponseInput(data); if (err) throw new Error(err); Type guard
function isDepartmentScopedPayload(data: unknown): data is { scope: 'department'; departmentId: string } {
return typeof data === 'object' && data !== null
&& (data as any).scope === 'department'
&& typeof (data as any).departmentId === 'string'
&& (data as any).departmentId.length > 0;
} Prevention
- Make the department selector a required field in the UI whenever scope is 'department'.
- Run the same scope/departmentId check in a shared validator on both client and server.
- Add a unit test that asserts the error for scope:'department' without departmentId.
When it happens
Trigger: Calling saveCannedResponse (or the cannedResponse.save meteor method / REST endpoint that delegates to it) with responseData.scope set to the literal string 'department' while omitting or leaving empty responseData.departmentId.
Common situations: UI form that lets the agent pick a scope dropdown but does not require the department selector when 'department' is chosen; a migration or seed script that hard-codes scope:'department' without setting departmentId; front-end bug where the department select is disabled/hidden but its value is not cleared.
Related errors
- error-invalid-sla
- error-invalid-user
- Invalid type
- Invalid service URL
- error-forwarding-department-target-not-allowed
AI-assisted analysis of RocketChat/Rocket.Chat@f9d3ec372b (2026-08-12).
Data as JSON: /api/errors/2f1de126885c682f.
Report an issue: GitHub.