{"record":{"id":"e754932056d8b391","repo":"invoke-ai/InvokeAI","slug":"an-image-move-job-is-already-running","errorCode":null,"errorMessage":"An image move job is already running","messagePattern":"An image move job is already running","errorType":"exception","errorClass":"ImageMoveJobAlreadyRunning","httpStatus":null,"severity":"error","filePath":"invokeai/app/services/image_moves/image_moves_default.py","lineNumber":145,"sourceCode":"        session_queue = self._session_queue\n        if session_queue is None and self._invoker is not None:\n            session_queue = getattr(self._invoker.services, \"session_queue\", None)\n        if session_queue is None:\n            return\n        queue_status = session_queue.get_queue_status(DEFAULT_QUEUE_ID)\n        if queue_status.pending > 0 or queue_status.in_progress > 0:\n            raise ImageMoveQueueActive(\"Cannot start image move while queue work is active\")\n\n    def _start_background_operation(\n        self,\n        operation: ImageMoveBackgroundOperation,\n        target,\n        require_idle_queue: bool = False,\n    ) -> ImageMoveBackgroundStatus:\n        with self._future_lock:\n            self._refresh_finished_future_locked()\n            if self._future_operation is not None or (self._future is not None and not self._future.done()):\n                raise ImageMoveJobAlreadyRunning(\"An image move job is already running\")\n            active_job_id = self._get_active_job_id()\n            if operation != \"recovery\" and active_job_id is not None:\n                raise ImageMoveJobAlreadyRunning(\"An image move job is already active\")\n            self._last_background_error = None\n            self._future_operation = operation\n\n        try:\n            if require_idle_queue:\n                self._assert_no_active_queue_work()\n            future = self._executor.submit(self._run_background_operation, operation, target)\n        except Exception:\n            with self._future_lock:\n                self._future_operation = None\n            raise\n\n        with self._future_lock:\n            self._future = future\n            return self._build_background_status_locked()","sourceCodeStart":127,"sourceCodeEnd":163,"githubUrl":"https://github.com/invoke-ai/InvokeAI/blob/0b6a024f2ff6a86bfb953dcdb9cc504ef7397a06/invokeai/app/services/image_moves/image_moves_default.py#L127-L163","documentation":"_start_background_operation refuses to start when a background operation is already tracked (self._future_operation set) or the running future is not done, raising ImageMoveJobAlreadyRunning('An image move job is already running'). Only one image-move background job may run at a time.","triggerScenarios":"Calling start_background_move_all or start_background_recovery twice without waiting for the first job's future to finish; an earlier job's future still marked as active because _refresh_finished_future_locked hasn't observed completion.","commonSituations":"Double-clicking a maintenance button in the UI; scheduled job overlapping a manual one; a hung previous move job never completing.","solutions":["Check get_status()/maintenance state first and only start when no job is active","Await the existing job's future (or call the stop endpoint and wait) before starting a new one","If a previous job is stuck, restart the service to clear in-memory state, then retry"],"exampleFix":"// before\nservice.start_background_move_all(target)\nservice.start_background_move_all(target)  # raises\n// after\nif not service.get_maintenance_status().is_maintenance_active:\n    service.start_background_move_all(target)","handlingStrategy":"validation","validationCode":"def can_start(service) -> bool:\n    return not service.get_maintenance_status().is_maintenance_active\nif can_start(service):\n    service.start_background_move_all(target)","typeGuard":null,"tryCatchPattern":"from invokeai.app.services.image_moves.image_moves_common import ImageMoveJobAlreadyRunning\ntry:\n    service.start_background_move_all(target)\nexcept ImageMoveJobAlreadyRunning:\n    logger.info('Move job already running; skipping duplicate start')","preventionTips":["Guard UI/automation triggers with a maintenance-active check","Keep a single entry point for starting move jobs in your code","Handle hung jobs by stopping/restarting rather than force-starting a second one"],"tags":["concurrency","background-job","state-conflict"],"backgroundTag":"job-already-running","analyzedSha":"0b6a024f2ff6a86bfb953dcdb9cc504ef7397a06","analyzedAt":"2026-08-29T04:46:49.967Z","schemaVersion":2},"datasetVersion":"2026-08-29T07:17:48.351Z"}