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
- Always set either details.userId (for normal users) or details.visitorToken (for livechat visitors) before creating the upload.
- Derive the actor from the incoming message/event that triggered the upload.
- 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
- Always attribute uploads to a user or livechat visitor.
- Derive the owner from the triggering message/event.
- Guard the details object before calling createUpload.
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
- Invalid Api parameter provided, it must be a valid IApi obje
- Invalid command parameter provided, must be a string.
- Invalid Slash Command parameter provided, it must be a valid
- The environmental variable "${envVarName}" is not readable.
- auth option should be of the form "username:password"
AI-assisted analysis of RocketChat/Rocket.Chat@f9d3ec372b (2026-08-12).
Data as JSON: /api/errors/f04219479c9807be.
Report an issue: GitHub.