RocketChat/Rocket.Chat · error · Error
error-invalid-room
error-invalid-room
Error message
error-invalid-room
What it means
Thrown by DELETE livechat/transcript/:rid when the room lookup returns null OR room.open is false. The endpoint cancels a previously-requested email transcript; cancellation only makes sense on an open conversation, so a missing or already-closed room is rejected before checking whether a transcript was requested.
Source
Thrown at apps/meteor/server/api/v1/omnichannel/transcript.ts:42
API.v1.addRoute(
'livechat/transcript/:rid',
{
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, {View on GitHub (pinned to f9d3ec372b)
Solutions
- Check room.open before offering the cancel-transcript action in the UI.
- If the room closed naturally, the transcript request is moot — no cancel needed; inform the user.
- Refresh the room state before issuing DELETE if the action has been pending in the UI.
- Handle this error gracefully as 'no action needed' rather than an error toast.
Example fix
// before
await DELETE('/api/v1/livechat/transcript/' + rid);
// after
const room = await fetchRoom(rid);
if (!room?.open) { notify('Room closed - transcript request cleared on close'); return; }
await DELETE('/api/v1/livechat/transcript/' + rid); Defensive patterns
Strategy: validation
Validate before calling
const room = await LivechatRooms.findOneById(rid, { projection: { open: 1, transcriptRequest: 1 } });
if (!room?.open) throw new ClientError('room-closed-or-missing'); Type guard
const isOpenForTranscript = (r: { open?: boolean; transcriptRequest?: unknown } | null): r is { open: true; transcriptRequest: unknown } =>
!!r && r.open === true; Try / catch
try {
await DELETE('/api/v1/livechat/transcript/' + rid);
} catch (e) {
if (e.message === 'error-invalid-room') { notify('Room is closed - nothing to cancel'); return; }
throw e;
} Prevention
- Only show the cancel-transcript control when room.open === true.
- Clear transcript-requested UI state when the room closes.
- Treat a closed-room cancel as a no-op, not an error.
When it happens
Trigger: DELETE /api/v1/livechat/transcript/<rid> against a room id that does not exist, or whose open flag is false. The projection only fetches open, transcriptRequest, v, so a closed room reaches this guard.
Common situations: User clicks 'cancel transcript' on a room that was just closed by the agent/inactivity; client holds a stale rid; race between close and the cancel click; transcript request was on a room that has since been deleted.
Related errors
- error-room-already-closed
- This_conversation_is_already_closed
- This_conversation_is_already_closed
- error-transcript-not-requested
- error-invalid-sla
AI-assisted analysis of RocketChat/Rocket.Chat@f9d3ec372b (2026-08-12).
Data as JSON: /api/errors/0924bbc83fea6167.
Report an issue: GitHub.