{"record":{"id":"0a0398de2772c761","repo":"RocketChat/Rocket.Chat","slug":"error-invalid-department-unit","errorCode":"error-invalid-department-unit","errorMessage":"Invalid department unit id provided","messagePattern":"Invalid department unit id provided","errorType":"error_code","errorClass":"Meteor.Error","httpStatus":null,"severity":"error","filePath":"apps/meteor/server/lib/omnichannel/departmentsLib.ts","lineNumber":31,"sourceCode":"import { notifyOnLivechatDepartmentAgentChangedByDepartmentId, notifyOnLivechatDepartmentAgentChanged } from '../notifyListener';\n/**\n * @param {string|null} _id - The department id\n * @param {Partial<import('@rocket.chat/core-typings').ILivechatDepartment>} departmentData\n * @param {{upsert?: { agentId: string; count?: number; order?: number; }[], remove?: { agentId: string; count?: number; order?: number; }}} [departmentAgents] - The department agents\n * @param {{_id?: string}} [departmentUnit] - The department's unit id\n */\nexport async function saveDepartment(\n\tuserId: string,\n\t_id: string | null,\n\tdepartmentData: LivechatDepartmentDTO,\n\tdepartmentAgents?: {\n\t\tupsert?: { agentId: string; count?: number; order?: number }[];\n\t\tremove?: { agentId: string; count?: number; order?: number }[];\n\t},\n\tdepartmentUnit?: { _id?: string },\n) {\n\tif (departmentUnit?._id !== undefined && typeof departmentUnit._id !== 'string') {\n\t\tthrow new Meteor.Error('error-invalid-department-unit', 'Invalid department unit id provided', {\n\t\t\tmethod: 'livechat:saveDepartment',\n\t\t});\n\t}\n\n\tconst department = _id\n\t\t? await LivechatDepartment.findOneById<Pick<ILivechatDepartment, '_id' | 'archived' | 'enabled' | 'parentId'>>(_id, {\n\t\t\t\tprojection: { _id: 1, archived: 1, enabled: 1, parentId: 1 },\n\t\t\t})\n\t\t: null;\n\n\tif (departmentUnit && !departmentUnit._id && department && department.parentId) {\n\t\tconst isLastDepartmentInUnit = (await LivechatDepartment.countDepartmentsInUnit(department.parentId)) === 1;\n\t\tif (isLastDepartmentInUnit) {\n\t\t\tthrow new Meteor.Error('error-unit-cant-be-empty', \"The last department in a unit can't be removed\", {\n\t\t\t\tmethod: 'livechat:saveDepartment',\n\t\t\t});\n\t\t}\n\t}","sourceCodeStart":13,"sourceCodeEnd":49,"githubUrl":"https://github.com/RocketChat/Rocket.Chat/blob/b2c16d5842cbe6b69b59bdf6fc5e5f1afcd1f0b0/apps/meteor/server/lib/omnichannel/departmentsLib.ts#L13-L49","documentation":"saveDepartment (POST/PUT /api/v1/livechat/departments) rejects the request when departmentUnit is provided with an _id that is defined but not a string — the guard is '_id !== undefined && typeof _id !== string'. So departmentUnit._id = null, 42, or an object fails, while omitting _id entirely is fine. It is a payload-shape error thrown as a Meteor.Error with method context 'livechat:saveDepartment'.","triggerScenarios":"Sending JSON like { departmentUnit: { _id: null } } (a common 'unset' idiom from serializers) or a numeric/object _id to the department save endpoint; note the REST layer passes departmentUnit || {}, so an empty object is safe but an explicit null _id is not.","commonSituations":"Client frameworks serializing empty references as null; sending unit number instead of its string id; API clients built against docs where _id was assumed optional-and-null.","solutions":["To keep the current unit: omit departmentUnit._id (or the whole departmentUnit object)","To assign a unit: send departmentUnit._id as the unit's string id","Fix client serialization so empty means absent key, not null"],"exampleFix":"// before\n{ name: 'Support', departmentUnit: { _id: null } }\n\n// after\n{ name: 'Support' } // no unit change\n// or\n{ name: 'Support', departmentUnit: { _id: 'unitId123' } }","handlingStrategy":"type-guard","validationCode":"if (departmentUnit !== undefined) {\n  if (departmentUnit._id !== undefined && typeof departmentUnit._id !== 'string') {\n    throw new TypeError('departmentUnit._id must be a string unit id or absent');\n  }\n}\nawait saveDepartment(userId, _id, departmentData, departmentAgents, departmentUnit);","typeGuard":"type DepartmentUnit = { _id?: string };\nconst isDepartmentUnit = (v: unknown): v is DepartmentUnit =>\n  v === undefined || (typeof v === 'object' && v !== null &&\n    ((v as DepartmentUnit)._id === undefined || typeof (v as DepartmentUnit)._id === 'string'));","tryCatchPattern":"try {\n  await saveDepartment(userId, _id, data, agents, departmentUnit);\n} catch (err) {\n  if (err instanceof Meteor.Error && (err as any).error === 'error-invalid-department-unit') {\n    // strip null _id from departmentUnit or send the unit's string id, then retry\n  }\n  throw err;\n}","preventionTips":["Serialize 'no unit' as an omitted key, never as _id: null","Type the request DTO so _id is string | undefined, not string | null","Add a request-schema check (AJV/zod) in clients that call department endpoints"],"tags":["omnichannel","livechat","departments","units","type-validation","rest-api"],"backgroundTag":"invalid-parameter-type","analyzedSha":"b2c16d5842cbe6b69b59bdf6fc5e5f1afcd1f0b0","analyzedAt":"2026-08-18T15:26:39.429Z","contentChangedAt":"2026-08-18T15:26:39.429Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}