RocketChat/Rocket.Chat · error · Error

Missing user to perform the upload operation

Error message

Missing user to perform the upload operation

What it means

Thrown by createUpload when the IUploadDetails has neither a userId nor a visitorToken. Every uploaded file must be attributed to either a logged-in user or a livechat visitor, so the bridge rejects details that lack both identity anchors before touching the Uploads store.

Source

Thrown at apps/meteor/app/apps/server/bridges/uploads.ts:49

	protected async getBuffer(upload: IUpload, appId: string): Promise<Buffer> {
		this.orch.debugLog(`The App ${appId} is getting the upload: "${upload.id}"`);

		const rocketChatUpload = this.orch.getConverters()?.get('uploads').convertToRocketChat(upload);

		const result = await FileUpload.getBuffer(rocketChatUpload);

		if (!(result instanceof Buffer)) {
			throw new Error('Unknown error');
		}

		return result;
	}

	protected async createUpload(details: IUploadDetails, buffer: Buffer, appId: string): Promise<IUpload> {
		this.orch.debugLog(`The App ${appId} is creating an upload "${details.name}"`);

		if (!details.userId && !details.visitorToken) {
			throw new Error('Missing user to perform the upload operation');
		}

		const fileStore = FileUpload.getStore('Uploads');

		details.type = determineFileType(buffer, details.name);

		const uploadedFile = await fileStore.insert(getUploadDetails(details), buffer);
		this.orch.debugLog(`The App ${appId} has created an upload`, uploadedFile);
		if (details.visitorToken) {
			await sendFileLivechatMessage({ roomId: details.rid, visitorToken: details.visitorToken, file: uploadedFile });
		} else {
			await sendFileMessage(details.userId, { roomId: details.rid, file: uploadedFile });
		}
		return this.orch.getConverters()?.get('uploads').convertToApp(uploadedFile);
	}
}

View on GitHub (pinned to f9d3ec372b)

Solutions

  1. Always set either details.userId (for normal users) or details.visitorToken (for livechat visitors) before creating the upload.
  2. Derive the actor from the incoming message/event that triggered the upload.
  3. Validate the details object with a guard before calling createUpload.

Example fix

// before
await modify.getUploader().upload({ name, size, rid });

// after
if (!details.userId && !details.visitorToken) {
  throw new Error('Cannot upload without an owning user or visitor');
}
await modify.getUploader().upload({ name, size, rid, userId: sender.id });
Defensive patterns

Strategy: validation

Validate before calling

if (!details.userId && !details.visitorToken) {
  throw new Error('Upload requires a userId or visitorToken');
}

Type guard

function hasUploadOwner(d: IUploadDetails): boolean {
  return Boolean(d.userId || d.visitorToken);
}

Prevention

When it happens

Trigger: App calls createUpload with a details object where both userId and visitorToken are undefined/empty. This happens when the app builds details from a context that had no actor (e.g. a webhook-triggered flow with no impersonation).

Common situations: App author forgets to set the actor; event payload that triggered the upload had no sender; livechat integration passes room id but omits the visitor token; testing without a user context.

Related errors


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