RocketChat/Rocket.Chat · error · Error
error-invalid-operation-status
Error message
error-invalid-operation-status
What it means
Rocket.Chat's import service drives a state machine: each Import document moves through statuses (uploading, preparing users, importer_user_selection, etc.) and ImportService.run() is the step that actually imports the selected users. run() only accepts the most recent operation when its status is exactly 'importer_user_selection'. This error means Imports.findLastImport() returned an operation in some other status, so the import cannot be started at this point in the flow.
Source
Thrown at apps/meteor/server/services/import/service.ts:162
roles: data.roles ? [...new Set([...data.roles, ...defaultRoles])] : defaultRoles,
},
dataType: 'user',
_updatedAt: new Date(),
})),
);
await Imports.increaseTotalCount(operation._id, 'users', users.length);
await Imports.setOperationStatus(operation._id, 'importer_user_selection');
}
public async run(userId: string): Promise<void> {
const operation = await Imports.findLastImport();
if (!operation?.valid) {
throw new Error('error-operation-not-found');
}
if (operation.status !== 'importer_user_selection') {
throw new Error('error-invalid-operation-status');
}
const { importerKey } = operation;
const importer = Importers.get(importerKey);
if (!importer) {
throw new Error('error-importer-not-defined');
}
// eslint-disable-next-line new-cap
const instance = new importer.importer(importer, operation, {
skipUserCallbacks: true,
skipDefaultChannels: true,
enableEmail2fa: settings.get<boolean>('Accounts_TwoFactorAuthentication_By_Email_Auto_Opt_In'),
quickUserInsertion: true,
skipExistingUsers: true,
});
await instance.startImport({ users: { all: true } }, userId);View on GitHub (pinned to b2c16d5842)
Solutions
- Re-enter the import UI and complete the pending steps (upload, prepare, select users) so the operation status becomes 'importer_user_selection', then start the import
- Before calling run(), fetch the last operation via Imports.findLastImport() and verify status === 'importer_user_selection'; abort with a clear message otherwise
- If a stale/failed operation is stuck in the wrong status, delete the last Import record (or finish it through the UI) so a fresh import can be created
- Make the client idempotent: disable the start button after first submission to prevent duplicate run() calls
Example fix
// before
await importService.run(userId); // throws error-invalid-operation-status
// after
const operation = await Imports.findLastImport();
if (!operation?.valid || operation.status !== 'importer_user_selection') {
throw new Error(`Import not ready to run (status: ${operation?.status ?? 'none'})`);
}
await importService.run(userId); Defensive patterns
Strategy: validation
Validate before calling
import { Imports } from '@rocket.chat/models';
async function assertImportReadyToRun(): Promise<void> {
const operation = await Imports.findLastImport();
if (!operation?.valid) throw new Error('error-operation-not-found');
if (operation.status !== 'importer_user_selection') {
throw new Error(`Import not ready (current status: ${operation.status})`);
}
} Type guard
type ImportOperation = Awaited<ReturnType<typeof Imports.findLastImport>>; const isReadyForUserImport = (op: ImportOperation): boolean => !!op?.valid && op.status === 'importer_user_selection';
Try / catch
try {
await importService.run(userId);
} catch (err) {
if (err instanceof Error && err.message === 'error-invalid-operation-status') {
// not retryable as-is: direct the user to finish the pending import step
return notifyUser('Complete the import steps before starting');
}
throw err;
} Prevention
- Drive the import wizard steps in order; never call run() before the user-selection step completes
- Always read the last operation's status before invoking run()
- Disable the start-import UI action after first submission to prevent double calls
When it happens
Trigger: Calling the import start flow (ImportService.run(), the 'startImport' action behind the import wizard) when the last Import record's status is anything other than 'importer_user_selection' — e.g. while the file is still uploading, while users are still being prepared, after the import already ran and moved the status forward, or after an earlier stage failed.
Common situations: Double-submitting the start-import action (second call sees a changed status); skipping the user-selection screen; a previous failed import left the last operation stuck in an intermediate status; two browser tabs driving the same import.
Understand the failure class
Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.
Related errors
- Import operation not initialized.
- The current import operation can not receive new data.
- The current import operation is already finished.
- error-operation-not-found
- error-importer-not-defined
AI-assisted analysis of RocketChat/Rocket.Chat@b2c16d5842 (2026-08-18).
Data as JSON: /api/errors/68b4de3236ddb746.
Report an issue: GitHub.