{"record":{"id":"cd4f574cd13afd9a","repo":"RocketChat/Rocket.Chat","slug":"not-found","errorCode":null,"errorMessage":"not-found","messagePattern":"not-found","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"apps/meteor/server/services/media-call/service.ts","lineNumber":62,"sourceCode":"\t\tthis.onEvent('watch.settings', async ({ setting }): Promise<void> => {\n\t\t\tif (setting._id.startsWith('VoIP_TeamCollab_')) {\n\t\t\t\tsetImmediate(() => this.configureMediaCallServer());\n\t\t\t}\n\t\t});\n\n\t\tthis.configureMediaCallServer();\n\t}\n\n\tpublic async answerCall(uid: IUser['_id'], params: Omit<ClientMediaSignalAnswer, 'type'>): Promise<IMediaCall> {\n\t\tconst { callId, answer } = params;\n\n\t\tconst call = await MediaCalls.findOneByIdAndCallee<Pick<IMediaCall, '_id'>>(\n\t\t\tcallId,\n\t\t\t{ type: 'user', id: uid },\n\t\t\t{ projection: { _id: 1 } },\n\t\t);\n\t\tif (!call) {\n\t\t\tthrow new Error('not-found');\n\t\t}\n\n\t\tconst signal: ClientMediaSignalAnswer = {\n\t\t\ttype: 'answer',\n\t\t\t...params,\n\t\t};\n\n\t\tawait callServer.receiveSignal(uid, signal, { throwIfSkipped: true });\n\n\t\tconst updatedCall = await MediaCalls.findOneById(callId);\n\t\tif (!updatedCall) {\n\t\t\tthrow new Error('internal-error');\n\t\t}\n\n\t\tswitch (answer) {\n\t\t\tcase 'ack':\n\t\t\t\tif (updatedCall.acceptedAt || updatedCall.ended) {\n\t\t\t\t\tthrow new Error('invalid-call-state');","sourceCodeStart":44,"sourceCodeEnd":80,"githubUrl":"https://github.com/RocketChat/Rocket.Chat/blob/b2c16d5842cbe6b69b59bdf6fc5e5f1afcd1f0b0/apps/meteor/server/services/media-call/service.ts#L44-L80","documentation":"MediaCallService.answerCall() verifies the incoming call exists and that the current user is its callee, via MediaCalls.findOneByIdAndCallee(callId, { type: 'user', id: uid }). 'not-found' means no call document matches that pair: the callId is wrong or expired, the call was already ended and removed, or the answering user is not the call's callee.","triggerScenarios":"Sending an answer signal with an expired or already-terminated callId; answering after the other side hung up (the MediaCalls document was deleted); answering from a user/session that is not the addressed callee.","commonSituations":"Client retries an answer after a network drop but the call timed out and was cleaned up; stale client call state after reconnect; race between caller cancelling and callee answering; duplicate ring/answer UI events.","solutions":["Treat 'not-found' as terminal: dismiss the ringing UI and clear local call state — do not retry the same callId","Before answering, re-sync the active call for this user and only answer the callId currently offered","Verify the answering user id matches the call's callee (same account, not a second user of the device)","De-duplicate answer submissions in the client so stale sessions cannot answer"],"exampleFix":"// before\nawait mediaCallService.answerCall(uid, { callId, answer: 'accept', /* ... */ });\n\n// after\nconst call = await MediaCalls.findOneByIdAndCallee(callId, { type: 'user', id: uid }, { projections: { _id: 1 } });\nif (!call) {\n  // call gone (ended, expired, or addressed to someone else): clean up, do not answer\n  return dismissRingingUI(callId);\n}\nawait mediaCallService.answerCall(uid, { callId, answer: 'accept', /* ... */ });","handlingStrategy":"validation","validationCode":"const call = await MediaCalls.findOneByIdAndCallee(callId, { type: 'user', id: uid }, { projections: { _id: 1 } });\nif (!call) {\n  // call ended, expired, or addressed to another user: do not send the answer\n  return clearLocalCallState(callId);\n}","typeGuard":"const isCallForUser = async (callId: string, uid: string): Promise<boolean> =>\n  Boolean(await MediaCalls.findOneByIdAndCallee(callId, { type: 'user', id: uid }, { projections: { _id: 1 } }));","tryCatchPattern":"try {\n  await mediaCallService.answerCall(uid, params);\n} catch (err) {\n  if (err instanceof Error && err.message === 'not-found') {\n    // terminal: drop the stale callId and dismiss the ringing UI — never retry it\n    return clearLocalCallState(params.callId);\n  }\n  throw err;\n}","preventionTips":["Expire ringing state client-side after the ring timeout instead of trusting old callIds","Re-sync the active call after reconnect before sending any signal","Never reuse callIds across sessions or tabs"],"tags":["webrtc","media-call","call-signaling","not-found","rocket-chat"],"backgroundTag":"call-not-found","analyzedSha":"b2c16d5842cbe6b69b59bdf6fc5e5f1afcd1f0b0","analyzedAt":"2026-08-18T15:26:39.429Z","contentChangedAt":"2026-08-18T15:26:39.429Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}