RocketChat/Rocket.Chat · error · Error

A video conference must exist to update.

Error message

A video conference must exist to update.

What it means

Thrown by the video conferences bridge update method when no existing video conference matches the provided call._id (or when _id is absent so the lookup is skipped). Update is a mutation on an existing record; the bridge loads the prior state via VideoConf.getUnfiltered and refuses to proceed if there is nothing to mutate.

Source

Thrown at apps/meteor/app/apps/server/bridges/videoConferences.ts:39

	}

	protected async create(call: AppVideoConference, appId: string): Promise<string> {
		this.orch.debugLog(`The App ${appId} is creating a video conference.`);

		return (
			await VideoConf.create({
				type: 'videoconference',
				...call,
			})
		).callId;
	}

	protected async update(call: VideoConference, appId: string): Promise<void> {
		this.orch.debugLog(`The App ${appId} is updating a video conference.`);

		const oldData = call._id && (await VideoConf.getUnfiltered(call._id));
		if (!oldData) {
			throw new Error('A video conference must exist to update.');
		}

		const data = (this.orch.getConverters()?.get('videoConferences') as AppVideoConferencesConverter).convertAppVideoConference(call);
		await VideoConf.setProviderData(call._id, data.providerData);

		for (const { _id, ts } of data.users) {
			if (oldData.users.find((user) => user._id === _id)) {
				continue;
			}

			await VideoConf.addUser(call._id, _id, ts);
		}

		if (data.endedBy && data.endedBy._id !== oldData.endedBy?._id) {
			await VideoConf.setEndedBy(call._id, data.endedBy._id);
		} else if (data.endedAt) {
			await VideoConf.setEndedAt(call._id, data.endedAt);
		}

View on GitHub (pinned to f9d3ec372b)

Solutions

  1. Ensure the video conference was created (create returned a callId) before calling update.
  2. Pass the exact callId returned by create as call._id.
  3. Re-fetch the conference before updating to confirm it still exists.

Example fix

// before
await videoConf.update({ ...staleCall, status: 'ended' });

// after
const existing = await VideoConf.getUnfiltered(callId);
if (!existing) {
  // conference already gone; nothing to update
  return;
}
await videoConf.update({ ...existing, status: 'ended' });
Defensive patterns

Strategy: validation

Validate before calling

if (!call._id) {
  throw new Error('Cannot update video conference: missing _id');
}
const existing = await VideoConf.getUnfiltered(call._id);
if (!existing) {
  throw new Error('Cannot update video conference: not found');
}

Type guard

function hasExistingCallId(call: VideoConference): call is VideoConference & { _id: string } {
  return typeof call._id === 'string' && call._id.length > 0;
}

Try / catch

try {
  await videoConf.update(call);
} catch (err) {
  if (err instanceof Error && err.message === 'A video conference must exist to update.') {
    // conference was deleted; create a new one instead
  } else {
    throw err;
  }
}

Prevention

When it happens

Trigger: App calls update with a call object whose _id is undefined, refers to a conference that was never created, or to one that has been deleted. The check is `const oldData = call._id && (await VideoConf.getUnfiltered(call._id)); if (!oldData) throw ...`.

Common situations: App updates a conference from a stale/cached object whose id no longer exists; conference ended and was cleaned up before the update; _id field stripped during serialization; race between create and update.

Related errors


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