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

  1. Remove the stale slaId from the visitor-info payload (omit the field, or pass the new SLA's id)
  2. Recreate an SLA with the referenced id if the reference must stay valid
  3. 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 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)