{"record":{"id":"3ecf942d3507c053","repo":"invoke-ai/InvokeAI","slug":"an-image-move-job-is-already-active","errorCode":null,"errorMessage":"An image move job is already active","messagePattern":"An image move job is already active","errorType":"exception","errorClass":"ImageMoveJobAlreadyRunning","httpStatus":null,"severity":"error","filePath":"invokeai/app/services/image_moves/image_moves_default.py","lineNumber":148,"sourceCode":"        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()\n\n    def _run_background_operation(self, operation: ImageMoveBackgroundOperation, target) -> None:\n        try:","sourceCodeStart":130,"sourceCodeEnd":166,"githubUrl":"https://github.com/invoke-ai/InvokeAI/blob/0b6a024f2ff6a86bfb953dcdb9cc504ef7397a06/invokeai/app/services/image_moves/image_moves_default.py#L130-L166","documentation":"Beyond the in-process future check, _start_background_operation consults _get_active_job_id (persisted/journaled active job). If an active job id exists and the requested operation is not 'recovery', it raises ImageMoveJobAlreadyRunning('An image move job is already active') — recovery is deliberately allowed to take over from a crashed run.","triggerScenarios":"Starting a new move while a journal/active-job record from a previous (possibly crashed) run exists; recovery interrupted by a non-recovery operation attempt with stale active job id.","commonSituations":"Server restarted mid-move leaving an uncommitted journal; previous job's active id never cleared due to a crash; attempting move_all before running recovery.","solutions":["Run start_background_recovery first to complete/commit the interrupted job and clear the active id","Clear or commit the stale journal entry via the maintenance/recovery API","Restart cleanly and complete recovery before scheduling new move operations"],"exampleFix":"// before\nservice.start_background_move_all(target)  # raises: active job id exists\n// after\nservice.start_background_recovery()  # finish interrupted job first\n# then, once recovery completes:\nservice.start_background_move_all(target)","handlingStrategy":"try-catch","validationCode":"def active_job_cleared(service) -> bool:\n    st = service.get_maintenance_status()\n    return not (st.is_maintenance_active or getattr(st, 'has_active_job', False))\nif active_job_cleared(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    service.start_background_recovery()  # clear stale active job, then retry\n    service.start_background_move_all(target)","preventionTips":["After a crash/restart, always run recovery before new move jobs","Monitor for uncommitted journals at startup","Serialize move-job scheduling through one worker/queue in your tooling"],"tags":["concurrency","journal","recovery","state-conflict"],"backgroundTag":"job-already-running","analyzedSha":"0b6a024f2ff6a86bfb953dcdb9cc504ef7397a06","analyzedAt":"2026-08-29T04:46:49.967Z","schemaVersion":2},"datasetVersion":"2026-08-29T07:17:48.351Z"}