{"record":{"id":"a6b5c2075cb847d1","repo":"RocketChat/Rocket.Chat","slug":"internal-error","errorCode":null,"errorMessage":"internal-error","messagePattern":"internal-error","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"apps/meteor/server/services/media-call/service.ts","lineNumber":74,"sourceCode":"\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');\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\tcase 'reject':\n\t\t\t\tif (!updatedCall.ended || updatedCall.endedBy?.id !== uid) {\n\t\t\t\t\tthrow new Error('invalid-call-state');\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\tcase 'accept':\n\t\t\t\tif (updatedCall.callee.contractId !== signal.contractId) {\n\t\t\t\t\tif (updatedCall.callee.contractId) {\n\t\t\t\t\t\tthrow new Error('invalid-call-state');\n\t\t\t\t\t}","sourceCodeStart":56,"sourceCodeEnd":92,"githubUrl":"https://github.com/RocketChat/Rocket.Chat/blob/b2c16d5842cbe6b69b59bdf6fc5e5f1afcd1f0b0/apps/meteor/server/services/media-call/service.ts#L56-L92","documentation":"A defensive guard in answerCall(): the call was found, the WebRTC signal was processed via callServer.receiveSignal(), but re-reading the call with MediaCalls.findOneById immediately afterwards returned nothing. The call document disappeared mid-operation — normally because the call was concurrently ended and deleted — so the post-signal state validation cannot continue and 'internal-error' is thrown.","triggerScenarios":"The other party (or a timeout sweeper) ends and removes the call between the initial findOneByIdAndCallee and the follow-up read inside answerCall — a race between answering and terminating the same call.","commonSituations":"Caller hangs up at the same moment the callee answers; call-expiry jobs removing calls during signaling; heavy load widening the race window; custom signaling clients sending delayed answers.","solutions":["Retry the flow from a fresh lookup: if the call is truly gone, surface 'call ended' to the user instead of an error","Check server logs for a concurrent end/timeout of the same callId to confirm the race","If it reproduces consistently with the call still present, inspect custom code paths that delete MediaCalls documents during signaling"],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":"// reduce (not eliminate) the window: confirm the call still exists right before answering\nconst call = await MediaCalls.findOneById(callId);\nif (!call || call.ended) {\n  return handleCallEnded(callId);\n}\nawait mediaCallService.answerCall(uid, params);","typeGuard":"const isLiveCall = (call: IMediaCall | null): call is IMediaCall => !!call && !call.ended;","tryCatchPattern":"try {\n  return await mediaCallService.answerCall(uid, params);\n} catch (err) {\n  if (err instanceof Error && err.message === 'internal-error') {\n    const stillExists = await MediaCalls.findOneById(params.callId);\n    if (!stillExists) return handleCallEnded(params.callId); // lost race with hangup: not an error for the user\n  }\n  throw err;\n}","preventionTips":["Act on remote 'ended' events immediately so answers are not sent for terminated calls","Keep signaling operations short to shrink race windows","Make clients tolerant of signals referencing calls that no longer exist"],"tags":["webrtc","media-call","race-condition","rocket-chat"],"backgroundTag":"database-race-condition","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"}