RocketChat/Rocket.Chat · error · Error
error-contact-not-found
error-contact-not-found
Error message
error-contact-not-found
What it means
disableContactById looks the contact up with findOneEnabledById and throws Error('error-contact-not-found') when nothing is returned - meaning the id matches no contact OR matches a contact that is already disabled. All downstream cleanup (guest removal across channels, contact disable) is skipped when this throws.
Source
Thrown at apps/meteor/server/lib/omnichannel/contacts/disableContact.ts:10
import type { ILivechatContact } from '@rocket.chat/core-typings';
import { LivechatContacts, LivechatRooms } from '@rocket.chat/models';
import { settings } from '../../../settings';
import { removeGuest } from '../guests';
export async function disableContactById(contactId: string): Promise<void> {
const contact = await LivechatContacts.findOneEnabledById<Pick<ILivechatContact, '_id' | 'channels'>>(contactId);
if (!contact) {
throw new Error('error-contact-not-found');
}
// Checking if the contact has any open channel/room before removing its data.
const contactOpenRooms = await LivechatRooms.checkContactOpenRooms(contactId);
if (contactOpenRooms && !settings.get<boolean>('Livechat_Allow_collect_and_store_HTTP_header_informations')) {
throw new Error('error-contact-has-open-rooms');
}
// Cleaning contact/visitor data;
await Promise.all(contact.channels.map((channel) => removeGuest({ _id: channel.visitor.visitorId })));
await LivechatContacts.disableByContactId(contactId);
}
View on GitHub (pinned to b2c16d5842)
Solutions
- Check for an enabled contact first and treat 'already disabled' as success in retry flows
- Resolve the correct contact id via search before disabling
- Debounce double submissions in the UI/API client
Example fix
// before - throws on the second call
await disableContactById(contactId);
// after - idempotent disable
const enabled = await LivechatContacts.findOneEnabledById(contactId, { projection: { _id: 1 } });
if (enabled) {
await disableContactById(contactId);
} Defensive patterns
Strategy: validation
Validate before calling
import { LivechatContacts } from '@rocket.chat/models';
// idempotent disable: only act when an enabled contact exists
const enabled = await LivechatContacts.findOneEnabledById(contactId, { projection: { _id: 1 } });
if (enabled) {
await disableContactById(contactId);
} Try / catch
try {
await disableContactById(contactId);
} catch (err: any) {
if (err?.message === 'error-contact-not-found') return; // already disabled or never existed
throw err;
} Prevention
- Make disable flows idempotent: check enabled state before disabling
- Debounce double-submits on contact management UIs
- Sync jobs should skip contacts that are already disabled
When it happens
Trigger: Disabling a contact twice (double submit or retry after timeout); a sync job re-processing contacts that were already disabled; passing a wrong or foreign contact id.
Common situations: Retry logic without idempotency awareness in integrations; nightly syncs that do not track disabled state; environment drift of contact ids.
Related errors
- error-contact-not-found
- error-visitor-not-found
- error-invalid-contact
- error-contact-not-found
- error-contact-not-found
AI-assisted analysis of RocketChat/Rocket.Chat@b2c16d5842 (2026-08-18).
Data as JSON: /api/errors/efdfa320b176a774.
Report an issue: GitHub.