RocketChat/Rocket.Chat · error · Error
SLA not found with id: ${slaId}
Error message
SLA not found with id: ${slaId} What it means
Thrown by updateSLA inside the onSaveVisitorInfo omnichannel hook when a non-empty slaId is supplied for a room but no document matches that id in the OmnichannelServiceLevelAgreements collection. It is a plain Error (not Meteor.Error). The SLA is looked up with a projection of _id/name/dueTimeInMinutes; passing an empty/undefined slaId instead routes to removeRoomSLA and never throws.
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 f9d3ec372b)
Solutions
- Verify the slaId still exists in OmnichannelServiceLevelAgreements before retrying (db query or the SLA list API).
- Re-fetch the available SLAs on the client and re-submit with a valid id, or send an empty slaId to clear it.
- Audit recently deleted SLAs and clean up references on rooms that still point to them.
Example fix
// before: blindly forward a stale id
await updateSLA(room, user, possiblyStaleSlaId);
// after: confirm existence first
const sla = await OmnichannelServiceLevelAgreements.findOneById(slaId);
if (!sla) {
// surface 'SLA not found' to user / pick a valid SLA instead
return removeRoomSLA(room._id, user);
}
await updateRoomSLA(room._id, user, sla); Defensive patterns
Strategy: validation
Validate before calling
async function safeUpdateSLA(room, user, slaId?: string) {
if (!slaId) return removeRoomSLA(room._id, user);
const sla = await OmnichannelServiceLevelAgreements.findOneById(slaId, { projection: { _id: 1, name: 1, dueTimeInMinutes: 1 } });
if (!sla) throw new Error(`SLA not found with id: ${slaId}`);
return updateRoomSLA(room._id, user, sla);
} Type guard
const isSlaRef = (id: unknown): id is string => typeof id === 'string' && id.trim().length > 0;
Try / catch
try { await onSaveVisitorInfo(...); } catch (e) {
if (e instanceof Error && e.message.startsWith('SLA not found with id')) {
// refresh SLA list on client, clear or repick slaId
} else throw e;
} Prevention
- Re-fetch SLA options right before submitting visitor info edits.
- Run a cleanup job that clears room.slaId when the SLA document is deleted.
- Pass undefined (not a stale id) when the user clears the SLA field.
When it happens
Trigger: Visitor info is saved (or room SLA is set) with an slaId referencing a deleted or never-created SLA record; a stale slaId is sent from a client after an admin removed the SLA; an integration passes a typo'd id.
Common situations: SLA was deleted between the time the client loaded the dropdown and the time the form was submitted; import/migration left rooms pointing at SLA ids that were not migrated; concurrent admin deletion.
Related errors
- error-action-not-allowed
- error-invalid-inquiry
- error-invalid-sla
- error-invalid-user
- Trigger is not configured to use an external service
AI-assisted analysis of RocketChat/Rocket.Chat@f9d3ec372b (2026-08-12).
Data as JSON: /api/errors/1393f0cc1a7dafd9.
Report an issue: GitHub.