RocketChat/Rocket.Chat · error · Error
error-not-authorized
Error message
error-not-authorized
What it means
Thrown inside applyDepartmentRestrictions (inquiries.ts:27-29) when an agent is department-restricted (they have one or more department assignments) and the requested `department` filter is not among their allowed departments. The allowed list is built from LivechatDepartmentAgents (by agentId) filtered through LivechatDepartment.findEnabledInIds. Returns HTTP 400 { success:false, error:'error-not-authorized' }.
Source
Thrown at apps/meteor/server/api/v1/omnichannel/lib/inquiries.ts:28
const agentDepartments = async (userId: IUser['_id']): Promise<string[]> => {
const agentDepartments = (await LivechatDepartmentAgents.findByAgentId(userId, { projection: { departmentId: 1 } }).toArray()).map(
({ departmentId }) => departmentId,
);
return (await LivechatDepartment.findEnabledInIds(agentDepartments, { projection: { _id: 1 } }).toArray()).map(({ _id }) => _id);
};
const applyDepartmentRestrictions = async (
userId: IUser['_id'],
filterDepartment?: string,
): Promise<{ $in: string[] } | { $exists: false } | string> => {
const allowedDepartments = await agentDepartments(userId);
if (allowedDepartments && Array.isArray(allowedDepartments) && allowedDepartments.length > 0) {
if (!filterDepartment) {
return { $in: allowedDepartments };
}
if (!allowedDepartments.includes(filterDepartment)) {
throw new Error('error-not-authorized');
}
return filterDepartment;
}
return { $exists: false };
};
export async function findInquiries({
userId,
department: filterDepartment,
status,
pagination: { offset, count, sort },
}: {
userId: IUser['_id'];
department?: string;
status?: LivechatInquiryStatus;
pagination: { offset: number; count: number; sort: Record<string, number> };
}): Promise<PaginatedResult<{ inquiries: Array<ILivechatInquiryRecord> }>> {View on GitHub (pinned to f9d3ec372b)
Solutions
- Omit the `department` filter so the server auto-scopes to the agent's own departments (the code returns { $in: allowedDepartments }).
- Request a department the agent actually belongs to.
- Grant the agent membership in the requested department (insert into LivechatDepartmentAgents) if cross-department visibility is intended.
Example fix
// before
findInquiries({ userId, department: 'deptB-not-mine', ... }); // throws error-not-authorized
// after
findInquiries({ userId, /* department omitted */ ... }); // auto-scoped to agent's departments Defensive patterns
Strategy: validation
Validate before calling
const allowed = (await LivechatDepartmentAgents.findByAgentId(userId, { projection: { departmentId: 1 } }).toArray())
.map((d) => d.departmentId);
if (filterDepartment && !allowed.includes(filterDepartment)) {
// drop the filter (auto-scope) or pick an allowed department
filterDepartment = undefined;
} Type guard
const isAgentDepartment = async (userId: string, deptId: string) => {
const set = new Set((await LivechatDepartmentAgents.findByAgentId(userId, { projection: { departmentId: 1 } }).toArray()).map((d) => d.departmentId));
return set.has(deptId);
}; Try / catch
try {
await findInquiries({ userId, department: filterDepartment, ... });
} catch (e) {
if (e instanceof Error && e.message === 'error-not-authorized') {
// retry without the department filter to auto-scope to allowed departments
await findInquiries({ userId, /* no department */ ... });
} else { throw e; }
} Prevention
- When unsure, omit the department filter so the server scopes to the agent's own departments.
- Keep the client's department picker limited to departments the agent belongs to.
- Refresh department membership when roles change.
When it happens
Trigger: Calling findInquiries (e.g. GET /livechat/inquiries) with a `department` query param naming a department the agent is not a member of, while the agent has at least one other department assignment.
Common situations: Agent scoped to Department A queries Department B's queue; department membership changed but the client keeps a cached department id; multi-tenant isolation enforced via department agents.
Related errors
- error-not-allowed
- error-forwarding-department-target-not-allowed
- error-not-allowed
- error-contact-not-found
- error-visitor-not-found
AI-assisted analysis of RocketChat/Rocket.Chat@f9d3ec372b (2026-08-12).
Data as JSON: /api/errors/1529fec449516664.
Report an issue: GitHub.