RocketChat/Rocket.Chat · error · Error
SLA not found with id
Error message
SLA not found with id: ${slaId} What it means
Plain Error thrown by updateSLA in the visitor-info save hook when the incoming visitor data carries an slaId but OmnichannelServiceLevelAgreements.findOneById(slaId) finds no SLA. The hook must convert the id into a full SLA record (name + dueTimeInMinutes) to update the room, so a dangling slaId aborts the visitor-info save with 'SLA not found with id: <id>'.
Solutions
- Remove the stale slaId from the visitor-info payload (omit the field, or pass the new SLA's id)
- Recreate an SLA with the referenced id if the reference must stay valid
- Audit rooms/visitors for dangling slaId references after deleting SLAs
Example fix
// before: saving visitor info with a possibly-dangling slaId
await saveVisitorInfo(visitorId, { ...info, slaId });
// after: validate the reference, or clear it, before saving
const sla = slaId
? await OmnichannelServiceLevelAgreements.findOneById(slaId, { projection: { _id: 1 } })
: null;
if (slaId && !sla) {
delete info.slaId; // or reassign to a current SLA id
}
await saveVisitorInfo(visitorId, { ...info, slaId }); Defensive patterns
Strategy: validation
Validate before calling
const slaIdIsLive = async (slaId?: string): Promise<boolean> =>
!slaId || Boolean(await OmnichannelServiceLevelAgreements.findOneById(slaId, { projection: { _id: 1 } })); Try / catch
try {
await saveVisitorInfo(visitorId, info);
} catch (err: any) {
if (err?.message?.startsWith('SLA not found with id:')) {
// strip the stale slaId from the payload and save again
}
throw err;
} Prevention
- When deleting an SLA, clear slaId from visitor records and widget configs that reference it
- Treat slaId as a foreign key: validate on write in integration code
- Keep SLA ids stable across environment syncs
When it happens
Trigger: Updating livechat visitor info (e.g. via the visitor API or contact management) with slaId from a deleted SLA; frontend holding a stale SLA selection; SLA purged during data cleanup while rooms/visitors still reference it.
Common situations: SLAs deleted after being assigned to visitors; environment syncs that drop SLA collections; integrations POSTing visitor fields including an old slaId.
Related errors
AI-assisted analysis of RocketChat/Rocket.Chat@b2c16d5842 (2026-08-18).
Data as JSON: /api/errors/1393f0cc1a7dafd9.
Report an issue: GitHub.
Appendix: source
Thrown at apps/meteor/ee/server/hooks/omnichannel/onSaveVisitorInfo.ts:18
import type { IOmnichannelRoom, IOmnichannelServiceLevelAgreements, IUser } from '@rocket.chat/core-typings';
import { OmnichannelServiceLevelAgreements } from '@rocket.chat/models';
import { callbacks } from '../../../../server/lib/callbacks';
import { removePriorityFromRoom, updateRoomPriority } from '../../api/v1/omnichannel/lib/priorities';
import { removeRoomSLA, updateRoomSLA } from '../../api/v1/omnichannel/lib/sla';
const updateSLA = async (room: IOmnichannelRoom, user: Required<Pick<IUser, '_id' | 'username' | 'name'>>, slaId?: string) => {
if (!slaId) {
return removeRoomSLA(room._id, user);
}
const sla: Pick<IOmnichannelServiceLevelAgreements, '_id' | 'name' | 'dueTimeInMinutes'> | null =
await OmnichannelServiceLevelAgreements.findOneById(slaId, {
projection: { _id: 1, name: 1, dueTimeInMinutes: 1 },
});
if (!sla) {
throw new Error(`SLA not found with id: ${slaId}`);
}
await updateRoomSLA(room._id, user, sla);
};
const updatePriority = async (room: IOmnichannelRoom, user: Required<Pick<IUser, '_id' | 'username' | 'name'>>, priorityId?: string) => {
if (!priorityId) {
return removePriorityFromRoom(room._id, user);
}
await updateRoomPriority(room._id, user, priorityId);
};
callbacks.add(
'livechat.saveInfo',
async (room, { user, oldRoom }: any) => {
const { slaId: oldSlaId, priorityId: oldPriorityId } = oldRoom;
const { slaId: newSlaId, priorityId: newPriorityId } = room;View on GitHub (pinned to b2c16d5842)