RocketChat/Rocket.Chat · error · Meteor.Error
error-not-authorized
error-not-authorized
Error message
Not authorized
What it means
Thrown when Upload.canDeleteFile(user, file, null) resolves false — the authenticated user is not allowed to delete this upload. With msg=null the service (apps/meteor/server/services/upload/service.ts:60) allows deletion only if: the file has both userId and rid, AND either it is an unconfirmed upload (expiresAt set) owned by the caller with room access, OR the caller passes canDeleteMessageAsync against a synthetic message built from the file's owner/timestamp/room — i.e. ownership or room-level delete-message permission is required.
Source
Thrown at apps/meteor/server/meteor-methods/messages/deleteFileMessage.ts:51
return deleteMessageValidatingPermission(msg, userId);
}
const user = await Users.findOneById(userId, { projection: { username: 1 } });
if (!user) {
throw new Meteor.Error('error-invalid-user', 'Invalid user', {
method: 'deleteFileMessage',
});
}
const file = await Uploads.findOneById(fileID, { projection: { userId: 1, rid: 1, expiresAt: 1, uploadedAt: 1 } });
if (!file) {
throw new Meteor.Error('error-invalid-file', 'Invalid file', {
method: 'deleteFileMessage',
});
}
if (!(await Upload.canDeleteFile(user, file, null))) {
throw new Meteor.Error('error-not-authorized', 'Not authorized', {
method: 'deleteFileMessage',
});
}
return FileUpload.getStore('Uploads').deleteById(fileID);
},
});
View on GitHub (pinned to b2c16d5842)
Solutions
- Only offer deletion when the caller owns the file (file.userId === Meteor.userId()) or holds delete-message rights in that room
- Grant or obtain the required room permission (e.g. moderator role with delete-message capability) and retry
- Have the file owner or a room admin perform the deletion
- Fix Uploads records that lack userId/rid — they can never be deleted through this path
Example fix
// before
Meteor.call('deleteFileMessage', file._id); // shown for everyone's files
// after
const canDelete = file.userId === Meteor.userId() || subscription?.roles?.includes('moderator');
if (canDelete) {
Meteor.call('deleteFileMessage', file._id);
} Defensive patterns
Strategy: validation
Validate before calling
const uid = Meteor.userId();
const canDelete = file.userId === uid
|| Boolean(subscription?.roles?.includes('moderator'))
|| Boolean(subscription?.roles?.includes('owner'));
if (!canDelete) {
// do not show/enable the delete action at all
}
Meteor.call('deleteFileMessage', file._id); Try / catch
try {
await Meteor.callAsync('deleteFileMessage', fileID);
} catch (e) {
if ((e as Meteor.Error).error === 'error-not-authorized') {
// inform the user they cannot delete this file; disable the action
}
} Prevention
- Derive the delete affordance from file ownership plus the user's subscription roles in that room
- Re-evaluate permissions when rendering, not only on load — roles change server-side
- Do not expose delete UI for other users' confirmed uploads unless the caller moderates the room
When it happens
Trigger: A non-owner calls deleteFileMessage for another user's confirmed upload without moderator delete permissions; the caller lacks room access for file.rid; the upload's userId/rid fields are missing entirely (canDeleteFile returns false for incomplete records).
Common situations: UI shows a delete affordance based on stale or incomplete data; shared channels where users assume they can remove others' files; permission roles changed after the UI rendered; orphaned uploads missing userId/rid.
Understand the failure class
Background: Permission denied / not authorized / 403 Forbidden: access-control rejections when the caller lacks the required role, grant, or ownership — this error's family across 18 libraries.
Related errors
AI-assisted analysis of RocketChat/Rocket.Chat@b2c16d5842 (2026-08-18).
Data as JSON: /api/errors/a7367cd5682583f4.
Report an issue: GitHub.