RocketChat/Rocket.Chat · error · Meteor.Error
invalid-file
invalid-file
Error message
invalid-file
What it means
Thrown by POST rooms.mediaConfirm/:rid/:fileId when no Uploads record matches the fileId, the calling user, AND the room simultaneously. The two-phase (Stream) upload flow stores the binary first and confirms later; this error means the confirmation step can't find that stored upload.
Source
Thrown at apps/meteor/server/api/v1/rooms.ts:338
},
});
},
},
);
API.v1.addRoute(
'rooms.mediaConfirm/:rid/:fileId',
{ authRequired: true },
{
async post() {
if (!(await canAccessRoomIdAsync(this.urlParams.rid, this.userId))) {
return API.v1.forbidden();
}
const file = await Uploads.findOneByIdAndUserIdAndRoomId(this.urlParams.fileId, this.userId, this.urlParams.rid);
if (!file) {
throw new Meteor.Error('invalid-file');
}
if ((this.bodyParams.description?.length ?? 0) > settings.get<number>('Message_MaxAllowedSize')) {
throw new Meteor.Error('error-message-size-exceeded');
}
file.description = this.bodyParams.description;
delete this.bodyParams.description;
if (this.bodyParams.fileName) {
file.name = this.bodyParams.fileName;
delete this.bodyParams.fileName;
}
if (this.bodyParams.fileContent) {
file.content = this.bodyParams.fileContent;
delete this.bodyParams.fileContent;
}View on GitHub (pinned to f9d3ec372b)
Solutions
- Make sure the upload phase (rooms.upload / the Streamer/UFS flow) returned a fileId before calling mediaConfirm.
- Pass the same rid and the authenticated user that created the upload.
- Confirm promptly — do not cache fileIds across long-running sessions or user switches.
- If this fires, re-run the full two-phase upload from scratch.
Example fix
// before
await rest.post(`/api/v1/rooms.mediaConfirm/${rid}/${guessedFileId}`);
// after
const start = await startUploadPhase(rid, file); // returns fileId
await rest.post(`/api/v1/rooms.mediaConfirm/${rid}/${start.fileId}`, {
description, fileName, fileContent,
}); Defensive patterns
Strategy: validation
Validate before calling
if (!fileId || typeof fileId !== 'string') {
throw new Error('mediaConfirm requires a fileId from the upload phase');
} Type guard
function isUploadRef(x: unknown): x is { fileId: string; rid: string } {
return !!x && typeof (x as any).fileId === 'string' && typeof (x as any).rid === 'string';
} Try / catch
try {
await rest.post(`/api/v1/rooms.mediaConfirm/${rid}/${fileId}`, body);
} catch (e) {
if (isMeteorError(e, 'invalid-file')) {
// restart the full two-phase upload
} else throw e;
} Prevention
- Always confirm with the same user and rid that created the upload.
- Confirm promptly; don't cache fileIds across sessions.
- Treat mediaConfirm as strictly paired with its upload phase.
When it happens
Trigger: POST /api/v1/rooms.mediaConfirm/:rid/:fileId where the fileId was never created, belongs to a different user, belongs to a different room, or was already consumed/cleaned up before confirmation.
Common situations: Calling mediaConfirm before the upload phase completed; using a fileId from a different session/user; replaying a confirm after the upload expired; race with upload cleanup; wrong rid in the URL.
Related errors
- error-no-file-uploaded
- Room not found
- error-room-param-not-provided
- error-room-not-found
- error-roomid-param-not-provided
AI-assisted analysis of RocketChat/Rocket.Chat@f9d3ec372b (2026-08-12).
Data as JSON: /api/errors/a8af4c44afdb9142.
Report an issue: GitHub.