RocketChat/Rocket.Chat · error · Meteor.Error

error-operation-not-found

error-operation-not-found

Error message

Import Operation Not Found

What it means

executeStartImport begins with `Imports.findLastImport()` and throws error-operation-not-found when the collection has no import operation. startImport continues the most recent import (file already uploaded and prepared); it cannot create one, so calling it before upload/preparation always fails this way.

Source

Thrown at apps/meteor/server/meteor-methods/import/startImport.ts:14

import type { IUser } from '@rocket.chat/core-typings';
import type { ServerMethods } from '@rocket.chat/ddp-client';
import { Imports } from '@rocket.chat/models';
import { isStartImportParamsPOST, type StartImportParamsPOST } from '@rocket.chat/rest-typings';
import { Meteor } from 'meteor/meteor';

import { hasPermissionAsync } from '../../lib/authorization/hasPermission';
import { methodDeprecationLogger } from '../../lib/deprecationWarningLogger';
import { Importers } from '../../lib/import';

export const executeStartImport = async ({ input }: StartImportParamsPOST, startedByUserId: IUser['_id']) => {
	const operation = await Imports.findLastImport();
	if (!operation) {
		throw new Meteor.Error('error-operation-not-found', 'Import Operation Not Found', 'startImport');
	}

	const { importerKey } = operation;
	const importer = Importers.get(importerKey);
	if (!importer) {
		throw new Meteor.Error('error-importer-not-defined', `The importer (${importerKey}) has no import class defined.`, 'startImport');
	}

	const instance = new importer.importer(importer, operation); // eslint-disable-line new-cap

	await instance.startImport(input, startedByUserId);
};

declare module '@rocket.chat/ddp-client' {
	// eslint-disable-next-line @typescript-eslint/naming-convention
	interface ServerMethods {
		startImport(params: StartImportParamsPOST): void;
	}

View on GitHub (pinned to b2c16d5842)

Solutions

  1. Run the full order: uploadImportFile → poll getImportFileData until it returns a selection → startImport with that selection
  2. If the operation vanished, re-upload the file to create a new one
  3. On 9.x use POST /v1/uploadImportFile and POST /v1/startImport

Example fix

// before
Meteor.call('startImport', { input: selection }, cb); // error-operation-not-found

// after — ensure an operation exists first
Meteor.call('getImportFileData', (e, data) => {
  if (e) { /* start with uploadImportFile */ return; }
  Meteor.call('startImport', { input: buildInput(data) });
});
Defensive patterns

Strategy: validation

Validate before calling

// Only call startImport once a prepared selection exists
Meteor.call('getImportFileData', (e, data) => {
  if (e) { /* upload first */ return; }
  if (data && !('waiting' in data)) Meteor.call('startImport', { input: toShortSelection(data) });
});

Type guard

const hasSelection = (d: IImporterSelection | { waiting: true } | undefined): d is IImporterSelection =>
  !!d && !('waiting' in d);

Try / catch

try {
  await meteorCall('startImport', { input });
} catch (e) {
  if (e instanceof Meteor.Error && e.error === 'error-operation-not-found') {
    // import vanished: restart from uploadImportFile
  }
}

Prevention

When it happens

Trigger: Calling `Meteor.call('startImport', { input })` before `uploadImportFile` has created an operation, or after the operation document was deleted between preparation and start.

Common situations: Clients that jump straight to startImport without the upload step; racing tabs where one cleared the import; retrying startImport after the operation was superseded by a new upload.

Related errors


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