{"record":{"id":"92d4779e8eb3ddf2","repo":"RocketChat/Rocket.Chat","slug":"error-transcript-not-requested","errorCode":"error-transcript-not-requested","errorMessage":"error-transcript-not-requested","messagePattern":"error-transcript-not-requested","errorType":"exception","errorClass":"Error","httpStatus":400,"severity":"warning","filePath":"apps/meteor/server/api/v1/omnichannel/transcript.ts","lineNumber":45,"sourceCode":"\t{\n\t\tauthRequired: true,\n\t\tpermissionsRequired: ['send-omnichannel-chat-transcript'],\n\t\tvalidateParams: {\n\t\t\tPOST: isPOSTLivechatTranscriptRequestParams,\n\t\t},\n\t},\n\t{\n\t\tasync delete() {\n\t\t\tconst { rid } = this.urlParams;\n\t\t\tconst room = await LivechatRooms.findOneById<Pick<IOmnichannelRoom, 'open' | 'transcriptRequest' | 'v'>>(rid, {\n\t\t\t\tprojection: { open: 1, transcriptRequest: 1, v: 1 },\n\t\t\t});\n\n\t\t\tif (!room?.open) {\n\t\t\t\tthrow new Error('error-invalid-room');\n\t\t\t}\n\t\t\tif (!room.transcriptRequest) {\n\t\t\t\tthrow new Error('error-transcript-not-requested');\n\t\t\t}\n\n\t\t\tif (!(await Omnichannel.isWithinMACLimit(room))) {\n\t\t\t\tthrow new Error('error-mac-limit-reached');\n\t\t\t}\n\n\t\t\tawait LivechatRooms.unsetEmailTranscriptRequestedByRoomId(rid);\n\n\t\t\treturn API.v1.success();\n\t\t},\n\t\tasync post() {\n\t\t\tconst { rid } = this.urlParams;\n\t\t\tconst { email, subject } = this.bodyParams;\n\n\t\t\tconst user = await Users.findOneById(this.userId, {\n\t\t\t\tprojection: { _id: 1, username: 1, name: 1, utcOffset: 1 },\n\t\t\t});\n","sourceCodeStart":27,"sourceCodeEnd":63,"githubUrl":"https://github.com/RocketChat/Rocket.Chat/blob/f9d3ec372bb580fa8d036f94cf03925a478ef768/apps/meteor/server/api/v1/omnichannel/transcript.ts#L27-L63","documentation":"Thrown by DELETE livechat/transcript/:rid when the room is open but room.transcriptRequest is unset. The endpoint's purpose is to cancel a pending email transcript; if none was ever requested there is nothing to cancel, so the guard rejects the call before the MAC check and the unset operation.","triggerScenarios":"DELETE /api/v1/livechat/transcript/<rid> on an open room where POST livechat/transcript/:rid (requestTranscript) was never called, or where the transcriptRequest field was already cleared (e.g. by a prior successful delete, or by the transcript being sent).","commonSituations":"User double-clicks cancel (second call hits this); UI shows a cancel button based on stale state; transcript was already sent/cleared by the system; client lost track of whether it requested a transcript.","solutions":["Track transcript-requested state in the client and only show 'cancel' when transcriptRequest is set.","Treat this error as a no-op success in the UI (idempotent cancel) rather than an error.","Refresh room.transcriptRequest before rendering the cancel control.","Guard against double-submit by disabling the button after the first click."],"exampleFix":"// before\nawait DELETE('/api/v1/livechat/transcript/' + rid);\n\n// after\nif (!room.transcriptRequest) { setTranscriptRequested(false); return; }\nawait DELETE('/api/v1/livechat/transcript/' + rid);\nsetTranscriptRequested(false);","handlingStrategy":"validation","validationCode":"const room = await LivechatRooms.findOneById(rid, { projection: { open: 1, transcriptRequest: 1 } });\nif (room?.open && !room.transcriptRequest) { setTranscriptRequested(false); return; /* nothing to cancel */ }","typeGuard":"const hasPendingTranscript = (r: { transcriptRequest?: unknown } | null): boolean => !!r?.transcriptRequest;","tryCatchPattern":"try {\n  await DELETE('/api/v1/livechat/transcript/' + rid);\n} catch (e) {\n  if (e.message === 'error-transcript-not-requested') { setTranscriptRequested(false); return; /* idempotent */ }\n  throw e;\n}","preventionTips":["Track transcript-requested state in the client; only show cancel when set.","Make cancel idempotent in the UI (second click is a no-op).","Refresh room.transcriptRequest before rendering the cancel control."],"tags":["omnichannel","livechat","transcript","state","validation","idempotency"],"backgroundTag":null,"analyzedSha":"f9d3ec372bb580fa8d036f94cf03925a478ef768","analyzedAt":"2026-08-12T19:07:17.372Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}