RocketChat/Rocket.Chat · error
A video conference must exist to update.
Error message
A video conference must exist to update.
What it means
The video-conferences bridge update path loads the existing call via VideoConf.getUnfiltered(call._id); when that returns nothing — the id is absent or no such call exists — it throws 'A video conference must exist to update.'. Updates are patches over an existing call record; there is no upsert here (creation goes through the separate create path).
Solutions
- Fetch the current call via the video-conference reader (getById) and update that fetched object.
- If no call exists yet, create it through the create path first, then update.
- Treat this error as 'call ended or removed' and stop tracking that call id.
Example fix
// before
await updateVideoConference(locallyBuiltCall, appId); // _id unset or unknown
// after
const call = await this.read.getVideoConferenceReader().getById(callId);
if (!call) {
return; // nothing to update; call does not exist
}
await updateVideoConference({ ...call, status }, appId); Defensive patterns
Strategy: validation
Validate before calling
const call = await this.read.getVideoConferenceReader().getById(callId);
if (!call) {
return; // call does not exist; nothing to update
} Type guard
const isExistingCall = (c: VideoConference | undefined | null): c is VideoConference & { _id: string } =>
Boolean(c && c._id); Try / catch
Catch and treat as 'call ended/removed': stop tracking the call id and clean up associated state.
Prevention
- Update only call objects fetched from the video-conference reader.
- Create calls through the provider flow before updating them.
- Re-validate stored call ids after restarts and long-running sessions.
When it happens
Trigger: App calls update with a VideoConference object whose _id is undefined or references a call that was never created through the provider flow; updating a call id from another deployment; updating after the call record was removed.
Common situations: Apps constructing a VideoConference object locally instead of fetching the live one; storing call refs across restarts; racing with call teardown/cleanup.
Understand the failure class
Background: Record Not Found Errors: "not found", RecordNotFound, and "was not found" — what they mean and how to fix them — this error's family across 28 libraries.
Related errors
- apps-engine-not-loaded
- error-invalid-provider
- failed-to-create-direct-call
- failed-to-create-group-call
- no-active-video-conf-provider
AI-assisted analysis of RocketChat/Rocket.Chat@b2c16d5842 (2026-08-18).
Data as JSON: /api/errors/a40a519ebebef4f2.
Report an issue: GitHub.
Appendix: 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 b2c16d5842)