invoke-ai/InvokeAI · error · ImageMoveJobAlreadyRunning

An image move job is already running

Error message

An image move job is already running

What it means

_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.

Source

Thrown at invokeai/app/services/image_moves/image_moves_default.py:145

        session_queue = self._session_queue
        if session_queue is None and self._invoker is not None:
            session_queue = getattr(self._invoker.services, "session_queue", None)
        if session_queue is None:
            return
        queue_status = session_queue.get_queue_status(DEFAULT_QUEUE_ID)
        if queue_status.pending > 0 or queue_status.in_progress > 0:
            raise ImageMoveQueueActive("Cannot start image move while queue work is active")

    def _start_background_operation(
        self,
        operation: ImageMoveBackgroundOperation,
        target,
        require_idle_queue: bool = False,
    ) -> ImageMoveBackgroundStatus:
        with self._future_lock:
            self._refresh_finished_future_locked()
            if self._future_operation is not None or (self._future is not None and not self._future.done()):
                raise ImageMoveJobAlreadyRunning("An image move job is already running")
            active_job_id = self._get_active_job_id()
            if operation != "recovery" and active_job_id is not None:
                raise ImageMoveJobAlreadyRunning("An image move job is already active")
            self._last_background_error = None
            self._future_operation = operation

        try:
            if require_idle_queue:
                self._assert_no_active_queue_work()
            future = self._executor.submit(self._run_background_operation, operation, target)
        except Exception:
            with self._future_lock:
                self._future_operation = None
            raise

        with self._future_lock:
            self._future = future
            return self._build_background_status_locked()

View on GitHub (pinned to 0b6a024f2f)

Solutions

  1. Check get_status()/maintenance state first and only start when no job is active
  2. Await the existing job's future (or call the stop endpoint and wait) before starting a new one
  3. If a previous job is stuck, restart the service to clear in-memory state, then retry

Example fix

// before
service.start_background_move_all(target)
service.start_background_move_all(target)  # raises
// after
if not service.get_maintenance_status().is_maintenance_active:
    service.start_background_move_all(target)
Defensive patterns

Strategy: validation

Validate before calling

def can_start(service) -> bool:
    return not service.get_maintenance_status().is_maintenance_active
if can_start(service):
    service.start_background_move_all(target)

Try / catch

from invokeai.app.services.image_moves.image_moves_common import ImageMoveJobAlreadyRunning
try:
    service.start_background_move_all(target)
except ImageMoveJobAlreadyRunning:
    logger.info('Move job already running; skipping duplicate start')

Prevention

When it happens

Trigger: 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.

Common situations: Double-clicking a maintenance button in the UI; scheduled job overlapping a manual one; a hung previous move job never completing.

Related errors


AI-assisted analysis of invoke-ai/InvokeAI@0b6a024f2f (2026-08-29). Data as JSON: /api/errors/e754932056d8b391. Report an issue: GitHub.