RocketChat/Rocket.Chat · error · Meteor.Error

error-invalid-file

error-invalid-file

Error message

Invalid file

What it means

Thrown when Uploads.findOneById(fileID) returns null: no Uploads document exists for the given id. By this point the method already established that no message references the file and that the caller is a valid user; the missing Uploads record is what fails. Deletion via this method only works for files tracked in the Uploads collection.

Source

Thrown at apps/meteor/server/meteor-methods/messages/deleteFileMessage.ts:45

		}
		check(fileID, String);

		const msg = await Messages.getMessageByFileId(fileID);

		if (msg) {
			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

  1. Re-verify the file id against a current Uploads record (refresh the file list) before deleting
  2. Make the flow idempotent: on 'error-invalid-file' during a retry, treat the file as already deleted and refresh UI state
  3. If Uploads records and the physical store disagree, reconcile the Uploads collection with the store (the standard delete path removes derivatives like thumbnails too)
  4. Prefer the supported REST path /v1/chat.delete for message-bound deletions

Example fix

// before
await Meteor.callAsync('deleteFileMessage', fileID);

// after — tolerate already-deleted files
try {
  await Meteor.callAsync('deleteFileMessage', fileID);
} catch (e) {
  if (e.error === 'error-invalid-file') {
    // already gone: update local state as deleted, do not retry
  } else {
    throw e;
  }
}
Defensive patterns

Strategy: try-catch

Validate before calling

const file = message?.files?.find((f) => f._id === fileID);
if (!file) {
  // id not referenced by any known message: refresh data before deleting
  return;
}
Meteor.call('deleteFileMessage', fileID);

Try / catch

try {
  await Meteor.callAsync('deleteFileMessage', fileID);
} catch (e) {
  if ((e as Meteor.Error).error === 'error-invalid-file') {
    // already deleted / unknown id: mark as removed locally, stop retrying
  } else {
    throw e;
  }
}

Prevention

When it happens

Trigger: Meteor.call('deleteFileMessage', fileID) with a mistyped id, a file whose Uploads record was already removed (earlier delete partially completed), or a file id copied from a different database/workspace.

Common situations: Double-click / double-submission of a delete button (second call finds nothing); ids transplanted between environments; Uploads and the GridFS store out of sync after an interrupted delete or partial migration.

Understand the failure class

Background: 'Could not be found', 'does not exist', 'not found in database': the resource-not-found family when an ID, slug, key, or URI lookup comes back empty — this error's family across 20 libraries.

Related errors


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