RocketChat/Rocket.Chat · error · Error

failed-to-create-direct-call

Error message

failed-to-create-direct-call

What it means

Thrown by startDirect() after the call document was created, the onNewVideoConference app event fired and maybeCreateDiscussion ran: getUnfiltered(callId) returns null. getUnfiltered bypasses room/user visibility filters, so null means the video_conference record itself is gone - typically a provider app handler deleted or moved it during runNewVideoConferenceEvent, a model hook removed it, or read-after-write inconsistency in the database.

Source

Thrown at apps/meteor/server/services/video-conference/service.ts:759

		const callId = await VideoConferenceModel.createDirect({
			...extraData,
			rid,
			createdBy: {
				_id: user._id,
				name: user.name as string,
				username: user.username as string,
			},
			providerName,
		});

		await this.runNewVideoConferenceEvent(callId);

		await this.maybeCreateDiscussion(callId, user);

		const call = (await this.getUnfiltered(callId)) as IDirectVideoConference | null;
		if (!call) {
			throw new Error('failed-to-create-direct-call');
		}
		const url = await this.generateNewUrl(call);
		await VideoConferenceModel.setUrlById(callId, url);

		const messageId = await this.createMessage(call, user);
		call.messages.started = messageId;
		await VideoConferenceModel.setMessageById(callId, 'started', messageId);

		// After 40 seconds if the status is still "calling", we cancel the call automatically.
		setTimeout(async () => {
			try {
				const call = await VideoConferenceModel.findOneById<IDirectVideoConference>(callId);

				if (call) {
					await this.endDirectCall(call);
					if (call.status !== VideoConferenceStatus.CALLING) {
						return;
					}

View on GitHub (pinned to e4b8178b20)

Solutions

  1. Inspect installed apps' onNewVideoConference handlers for deletion/recreation logic and fix or remove the offending app
  2. Check the video_conference collection to confirm the doc exists right after create (distinguishes deletion from failed insert)
  3. If using a replica set, ensure reads for this path hit the primary or tolerate replication lag
  4. Retry the start call once - transient races resolve on a second attempt

Example fix

// before
const call = await getUnfiltered(callId);
if (!call) throw new Error('failed-to-create-direct-call');

// after
let call = await getUnfiltered(callId);
if (!call) {
	await new Promise((r) => setTimeout(r, 100));
	call = await getUnfiltered(callId); // tolerate replication lag / handler rewrite
}
if (!call) throw new Error('failed-to-create-direct-call');
Defensive patterns

Strategy: try-catch

Try / catch

try {
	await videoConfService.startCall(user, { _id: rid, uids });
} catch (err) {
	if (err instanceof Error && err.message === 'failed-to-create-direct-call') {
		// log callId context, inspect provider app handlers, then surface a retry to the user
	}
}

Prevention

When it happens

Trigger: A provider app's new-conference handler removes or recreates the call doc during creation; a DB observer/hook deletes it; in replica-set deployments the read routes to a secondary that has not yet applied the insert.

Common situations: Custom provider apps that 'clean up' calls they do not recognize; app versions whose handlers reject unconfigured providers; local dev against a lagging mongod replica set.

Related errors


AI-assisted analysis of RocketChat/Rocket.Chat@e4b8178b20 (2026-08-18). Data as JSON: /api/errors/3f109af45df9f27b. Report an issue: GitHub.