RocketChat/Rocket.Chat · warning · Error

error-transcript-not-requested

error-transcript-not-requested

Error message

error-transcript-not-requested

What it means

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.

Source

Thrown at apps/meteor/server/api/v1/omnichannel/transcript.ts:45

	{
		authRequired: true,
		permissionsRequired: ['send-omnichannel-chat-transcript'],
		validateParams: {
			POST: isPOSTLivechatTranscriptRequestParams,
		},
	},
	{
		async delete() {
			const { rid } = this.urlParams;
			const room = await LivechatRooms.findOneById<Pick<IOmnichannelRoom, 'open' | 'transcriptRequest' | 'v'>>(rid, {
				projection: { open: 1, transcriptRequest: 1, v: 1 },
			});

			if (!room?.open) {
				throw new Error('error-invalid-room');
			}
			if (!room.transcriptRequest) {
				throw new Error('error-transcript-not-requested');
			}

			if (!(await Omnichannel.isWithinMACLimit(room))) {
				throw new Error('error-mac-limit-reached');
			}

			await LivechatRooms.unsetEmailTranscriptRequestedByRoomId(rid);

			return API.v1.success();
		},
		async post() {
			const { rid } = this.urlParams;
			const { email, subject } = this.bodyParams;

			const user = await Users.findOneById(this.userId, {
				projection: { _id: 1, username: 1, name: 1, utcOffset: 1 },
			});

View on GitHub (pinned to f9d3ec372b)

Solutions

  1. Track transcript-requested state in the client and only show 'cancel' when transcriptRequest is set.
  2. Treat this error as a no-op success in the UI (idempotent cancel) rather than an error.
  3. Refresh room.transcriptRequest before rendering the cancel control.
  4. Guard against double-submit by disabling the button after the first click.

Example fix

// before
await DELETE('/api/v1/livechat/transcript/' + rid);

// after
if (!room.transcriptRequest) { setTranscriptRequested(false); return; }
await DELETE('/api/v1/livechat/transcript/' + rid);
setTranscriptRequested(false);
Defensive patterns

Strategy: validation

Validate before calling

const room = await LivechatRooms.findOneById(rid, { projection: { open: 1, transcriptRequest: 1 } });
if (room?.open && !room.transcriptRequest) { setTranscriptRequested(false); return; /* nothing to cancel */ }

Type guard

const hasPendingTranscript = (r: { transcriptRequest?: unknown } | null): boolean => !!r?.transcriptRequest;

Try / catch

try {
  await DELETE('/api/v1/livechat/transcript/' + rid);
} catch (e) {
  if (e.message === 'error-transcript-not-requested') { setTranscriptRequested(false); return; /* idempotent */ }
  throw e;
}

Prevention

When it happens

Trigger: 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).

Common situations: 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.

Related errors


AI-assisted analysis of RocketChat/Rocket.Chat@f9d3ec372b (2026-08-12). Data as JSON: /api/errors/92d4779e8eb3ddf2. Report an issue: GitHub.