{"record":{"id":"68b4de3236ddb746","repo":"RocketChat/Rocket.Chat","slug":"error-invalid-operation-status","errorCode":null,"errorMessage":"error-invalid-operation-status","messagePattern":"error-invalid-operation-status","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"apps/meteor/server/services/import/service.ts","lineNumber":162,"sourceCode":"\t\t\t\t\troles: data.roles ? [...new Set([...data.roles, ...defaultRoles])] : defaultRoles,\n\t\t\t\t},\n\t\t\t\tdataType: 'user',\n\t\t\t\t_updatedAt: new Date(),\n\t\t\t})),\n\t\t);\n\n\t\tawait Imports.increaseTotalCount(operation._id, 'users', users.length);\n\t\tawait Imports.setOperationStatus(operation._id, 'importer_user_selection');\n\t}\n\n\tpublic async run(userId: string): Promise<void> {\n\t\tconst operation = await Imports.findLastImport();\n\t\tif (!operation?.valid) {\n\t\t\tthrow new Error('error-operation-not-found');\n\t\t}\n\n\t\tif (operation.status !== 'importer_user_selection') {\n\t\t\tthrow new Error('error-invalid-operation-status');\n\t\t}\n\n\t\tconst { importerKey } = operation;\n\t\tconst importer = Importers.get(importerKey);\n\t\tif (!importer) {\n\t\t\tthrow new Error('error-importer-not-defined');\n\t\t}\n\n\t\t// eslint-disable-next-line new-cap\n\t\tconst instance = new importer.importer(importer, operation, {\n\t\t\tskipUserCallbacks: true,\n\t\t\tskipDefaultChannels: true,\n\t\t\tenableEmail2fa: settings.get<boolean>('Accounts_TwoFactorAuthentication_By_Email_Auto_Opt_In'),\n\t\t\tquickUserInsertion: true,\n\t\t\tskipExistingUsers: true,\n\t\t});\n\n\t\tawait instance.startImport({ users: { all: true } }, userId);","sourceCodeStart":144,"sourceCodeEnd":180,"githubUrl":"https://github.com/RocketChat/Rocket.Chat/blob/b2c16d5842cbe6b69b59bdf6fc5e5f1afcd1f0b0/apps/meteor/server/services/import/service.ts#L144-L180","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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"],"exampleFix":"// before\nawait importService.run(userId); // throws error-invalid-operation-status\n\n// after\nconst operation = await Imports.findLastImport();\nif (!operation?.valid || operation.status !== 'importer_user_selection') {\n  throw new Error(`Import not ready to run (status: ${operation?.status ?? 'none'})`);\n}\nawait importService.run(userId);","handlingStrategy":"validation","validationCode":"import { Imports } from '@rocket.chat/models';\n\nasync function assertImportReadyToRun(): Promise<void> {\n  const operation = await Imports.findLastImport();\n  if (!operation?.valid) throw new Error('error-operation-not-found');\n  if (operation.status !== 'importer_user_selection') {\n    throw new Error(`Import not ready (current status: ${operation.status})`);\n  }\n}","typeGuard":"type ImportOperation = Awaited<ReturnType<typeof Imports.findLastImport>>;\nconst isReadyForUserImport = (op: ImportOperation): boolean =>\n  !!op?.valid && op.status === 'importer_user_selection';","tryCatchPattern":"try {\n  await importService.run(userId);\n} catch (err) {\n  if (err instanceof Error && err.message === 'error-invalid-operation-status') {\n    // not retryable as-is: direct the user to finish the pending import step\n    return notifyUser('Complete the import steps before starting');\n  }\n  throw err;\n}","preventionTips":["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"],"tags":["import","state-machine","status-check","rocket-chat"],"backgroundTag":"invalid-state-transition","analyzedSha":"b2c16d5842cbe6b69b59bdf6fc5e5f1afcd1f0b0","analyzedAt":"2026-08-18T15:26:39.429Z","schemaVersion":2},"datasetVersion":"2026-08-22T04:17:13.399Z"}