{"record":{"id":"fcdfd66cd3bb0c67","repo":"RocketChat/Rocket.Chat","slug":"error-contact-not-found-fcdfd6","errorCode":"error-contact-not-found","errorMessage":"error-contact-not-found","messagePattern":"error-contact-not-found","errorType":"error_code","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"apps/meteor/server/lib/omnichannel/contacts/updateContact.ts","lineNumber":37,"sourceCode":"\tphones?: string[];\n\tcustomFields?: Record<string, unknown>;\n\tcontactManager?: string;\n\tchannels?: ILivechatContactChannel[];\n\twipeConflicts?: boolean;\n};\n\nexport async function updateContact(params: UpdateContactParams): Promise<ILivechatContact> {\n\tconst { contactId, name, emails, phones, customFields: receivedCustomFields, contactManager, channels, wipeConflicts } = params;\n\n\tconst contact = await LivechatContacts.findOneEnabledById<Pick<ILivechatContact, '_id' | 'name' | 'customFields' | 'conflictingFields'>>(\n\t\tcontactId,\n\t\t{\n\t\t\tprojection: { _id: 1, name: 1, customFields: 1, conflictingFields: 1 },\n\t\t},\n\t);\n\n\tif (!contact) {\n\t\tthrow new Error('error-contact-not-found');\n\t}\n\n\tif (contactManager) {\n\t\tawait validateContactManager(contactManager);\n\t}\n\n\tif (wipeConflicts && contact.conflictingFields?.length) {\n\t\tconst value = await Settings.incrementValueById('Resolved_Conflicts_Count', contact.conflictingFields.length, {\n\t\t\treturnDocument: 'after',\n\t\t});\n\t\tif (value) {\n\t\t\tvoid notifyOnSettingChanged(value);\n\t\t}\n\t}\n\n\tconst workspaceAllowedCustomFields = await getAllowedCustomFields();\n\tconst workspaceAllowedCustomFieldsIds = workspaceAllowedCustomFields.map((customField) => customField._id);\n\tconst currentCustomFieldsIds = Object.keys(contact.customFields || {});","sourceCodeStart":19,"sourceCodeEnd":55,"githubUrl":"https://github.com/RocketChat/Rocket.Chat/blob/b2c16d5842cbe6b69b59bdf6fc5e5f1afcd1f0b0/apps/meteor/server/lib/omnichannel/contacts/updateContact.ts#L19-L55","documentation":"updateContact (PUT /api/v1/omnichannel/contact) loads the contact via LivechatContacts.findOneEnabledById with only _id, name, customFields, conflictingFields projected. If contactId does not match an enabled contact, this error is thrown before any validation of the update payload. Both unknown ids and disabled contacts land here.","triggerScenarios":"PUT /omnichannel/contact with a contactId that is wrong, stale, or refers to a contact with enabled:false; also triggered when a client sends the visitor token or room id where the contact _id is expected.","commonSituations":"Client persists a contactId across restarts and the contact was since deleted; contact disabled by a merge process; confusion between visitorId/token and contactId in integrations.","solutions":["GET /api/v1/omnichannel/contact with the same contactId to confirm it exists and is enabled","Make sure you pass the contact _id (from the register/list response), not the visitor token or visitorId","If the contact was disabled, find and update the active contact that replaced it"],"exampleFix":null,"handlingStrategy":"validation","validationCode":"const contact = await LivechatContacts.findOneEnabledById(contactId, { projection: { _id: 1 } });\nif (!contact) throw new Error(`No enabled contact ${contactId}`);\nawait updateContact(params);","typeGuard":"const isContactId = (v: unknown): v is string => typeof v === 'string' && /^[0-9a-f]{17}$/i.test(v) && v !== token && v !== visitorId;","tryCatchPattern":"try {\n  await updateContact(params);\n} catch (err) {\n  if (err instanceof Error && err.message === 'error-contact-not-found') {\n    // verify id source: must be contact._id, not token/visitorId; check contact not disabled\n  }\n  throw err;\n}","preventionTips":["Store the contactId returned by registerContact, distinct from visitor token/id","Validate id shape client-side (17-hex ObjectID)","Refresh contact ids after merges or imports"],"tags":["omnichannel","livechat","contacts","not-found","validation"],"backgroundTag":"resource-not-found","analyzedSha":"b2c16d5842cbe6b69b59bdf6fc5e5f1afcd1f0b0","analyzedAt":"2026-08-18T15:26:39.429Z","schemaVersion":2},"datasetVersion":"2026-08-21T13:17:26.733Z"}