{"record":{"id":"15d3e8ed44e8ff7f","repo":"RocketChat/Rocket.Chat","slug":"error-inquiry-taken","errorCode":"error-inquiry-taken","errorMessage":"error-inquiry-taken","messagePattern":"error-inquiry-taken","errorType":"exception","errorClass":"Meteor.Error","httpStatus":null,"severity":"warning","filePath":"apps/meteor/server/lib/omnichannel/takeInquiry.ts","lineNumber":24,"sourceCode":"import { isAgentAvailableToTakeContactInquiry } from './contacts/isAgentAvailableToTakeContactInquiry';\nimport { migrateVisitorIfMissingContact } from './contacts/migrateVisitorIfMissingContact';\nimport { settings } from '../../settings';\n\nexport const takeInquiry = async (\n\tuserId: string,\n\tinquiryId: string,\n\toptions?: { clientAction: boolean; forwardingToDepartment?: { oldDepartmentId: string; transferData: any } },\n): Promise<void> => {\n\tconst inquiry = await LivechatInquiry.findOneById(inquiryId);\n\n\tif (!inquiry) {\n\t\tthrow new Meteor.Error('error-not-found', 'Inquiry not found', {\n\t\t\tmethod: 'livechat:takeInquiry',\n\t\t});\n\t}\n\n\tif (inquiry.status === 'taken') {\n\t\tthrow new Meteor.Error('error-inquiry-taken', 'Inquiry already taken', {\n\t\t\tmethod: 'livechat:takeInquiry',\n\t\t});\n\t}\n\n\tconst user = await Users.findOneOnlineAgentById(\n\t\tuserId,\n\t\tsettings.get<boolean>('Livechat_enabled_when_agent_idle'),\n\t\tsettings.get<boolean>('Livechat_accept_chats_with_no_agents'),\n\t\t{},\n\t);\n\tif (!user) {\n\t\tthrow new Meteor.Error('error-agent-status-service-offline', 'Agent status is offline or Omnichannel service is not active', {\n\t\t\tmethod: 'livechat:takeInquiry',\n\t\t\t...(process.env.TEST_MODE && {\n\t\t\t\tLivechat_enabled_when_agent_idle: settings.get<boolean>('Livechat_enabled_when_agent_idle'),\n\t\t\t\tLivechat_accept_chats_with_no_agents: settings.get<boolean>('Livechat_accept_chats_with_no_agents'),\n\t\t\t\tuser: await Users.findOneById(userId),\n\t\t\t}),","sourceCodeStart":6,"sourceCodeEnd":42,"githubUrl":"https://github.com/RocketChat/Rocket.Chat/blob/b2c16d5842cbe6b69b59bdf6fc5e5f1afcd1f0b0/apps/meteor/server/lib/omnichannel/takeInquiry.ts#L6-L42","documentation":"takeInquiry refuses to grab an inquiry whose status is already 'taken': it throws Meteor.Error('error-inquiry-taken', 'Inquiry already taken', { method: 'livechat:takeInquiry' }). This is the deliberate concurrency guard for two agents claiming the same queued conversation — the document's status field is the source of truth, checked before the room is reassigned.","triggerScenarios":"Two agents (or an agent and an auto-assignment routine) call livechat:takeInquiry for the same inquiry within the same window; the loser of the race reads status 'taken' and gets this error. Also a single client double-clicking take, or a retry after a slow first call that actually succeeded.","commonSituations":"High-traffic queues where several agents click the same lead, duplicate submissions from flaky UIs, retries that don't check whether the first take succeeded, bots racing human agents.","solutions":["Treat 'error-inquiry-taken' as a normal outcome: catch it, update the local queue, and move on — do not blindly retry","Guard the take button against double-clicks while a take request is in flight","Subscribe to the livechat inquiry stream so taken entries disappear immediately from all clients","On retry-after-timeout, first re-fetch the inquiry status instead of re-taking"],"exampleFix":"// before\nawait Meteor.callAsync('livechat:takeInquiry', inquiryId);\n\n// after\ntry {\n  await Meteor.callAsync('livechat:takeInquiry', inquiryId);\n} catch (err) {\n  if (err?.error === 'error-inquiry-taken') return removeInquiryLocally(inquiryId);\n  throw err;\n}","handlingStrategy":"try-catch","validationCode":"import { LivechatInquiry } from '@rocket.chat/models';\n\nconst inquiry = await LivechatInquiry.findOneById(inquiryId);\nif (inquiry?.status === 'taken') {\n  return removeInquiryLocally(inquiryId); // lost the race; nothing to do\n}\nawait Meteor.callAsync('livechat:takeInquiry', inquiryId);","typeGuard":"function isTakeableInquiry(v: { status?: string } | null | undefined): v is { _id: string; status: 'queued' } {\n  return !!v && v.status === 'queued';\n}","tryCatchPattern":"try {\n  await Meteor.callAsync('livechat:takeInquiry', inquiryId);\n} catch (err) {\n  if (err instanceof Meteor.Error && err.error === 'error-inquiry-taken') {\n    // expected race outcome: drop the entry from the UI, do NOT retry the take\n  } else {\n    throw err;\n  }\n}","preventionTips":["Disable the take button while a take request is in flight (no double-clicks)","Design queue UIs assuming any entry can be taken by someone else at any moment","On retry-after-timeout, first check whether your take already succeeded"],"tags":["omnichannel","inquiry","concurrency","race-condition","queue"],"backgroundTag":"concurrent-modification-conflict","analyzedSha":"b2c16d5842cbe6b69b59bdf6fc5e5f1afcd1f0b0","analyzedAt":"2026-08-18T15:26:39.429Z","contentChangedAt":"2026-08-18T15:26:39.429Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}