HumanSignal/label-studio · error · ValueError

Storage status ({self.status}) must be QUEUED to move it IN_

Error message

Storage status ({self.status}) must be QUEUED to move it IN_PROGRESS

What it means

ImportStorage synchronizations follow a strict state machine: a scan may only start from QUEUED. info_set_in_progress raises this ValueError if the storage's current status is anything other than QUEUED (e.g. already IN_PROGRESS, FAILED, or COMPLETED), preventing concurrent or invalid transitions from clobbering state-reset logic.

Source

Thrown at label_studio/io_storages/base_models.py:128

            if locked_storage.status in [self.Status.QUEUED, self.Status.IN_PROGRESS]:
                logger.error(
                    f'Storage {locked_storage} (id={locked_storage.id}) is already in status '
                    f'"{locked_storage.status}". Cannot set to QUEUED. '
                    f'Last sync job: {locked_storage.last_sync_job}, '
                    f'Meta: {locked_storage.meta}'
                )
                return False

            locked_storage._update_queued_status()

            self.refresh_from_db()
            return True

    def info_set_in_progress(self):
        # only QUEUED => IN_PROGRESS transition is possible, because in QUEUED we reset states
        if self.status != self.Status.QUEUED:
            raise ValueError(f'Storage status ({self.status}) must be QUEUED to move it IN_PROGRESS')
        self.status = self.Status.IN_PROGRESS

        dt = timezone.now()
        self.meta['time_in_progress'] = str(dt)
        # at the very beginning it's the same as in progress time
        self.meta['time_last_ping'] = str(dt)
        self.save(update_fields=['status', 'meta'])

    @property
    def time_in_progress(self):
        if 'time_failure' not in self.meta:
            return datetime.fromisoformat(self.meta['time_in_progress'])
        else:
            return datetime.fromisoformat(self.meta['time_failure'])

    def info_set_completed(self, last_sync_count, **kwargs):
        self.status = self.Status.COMPLETED
        self.last_sync = timezone.now()

View on GitHub (pinned to 0b49e9b539)

Solutions

  1. Wait for the current synchronization to finish, or check the storage status in the UI/API before triggering another sync.
  2. Reset the storage status to QUEUED (e.g. via the storage status endpoint or by re-saving the storage) and retry.
  3. Fix the crashed earlier sync (check logs for the underlying failure) so the status transitions back to QUEUED.

Example fix

// before
storage.info_set_in_progress()  # may raise if status != QUEUED

// after
storage.refresh_from_db()
if storage.status == storage.Status.QUEUED:
    storage.info_set_in_progress()
else:
    logger.warning('Storage %s sync skipped, status=%s', storage.pk, storage.status)
Defensive patterns

Strategy: validation

Validate before calling

storage.refresh_from_db()
if storage.status != storage.Status.QUEUED:
    logger.warning('Skipping sync: storage status is %s', storage.status)
    return

Type guard

def can_start_sync(storage) -> bool:
    return storage.status == storage.Status.QUEUED

Try / catch

try:
    storage.info_set_in_progress()
except ValueError as e:
    logger.warning('Sync not started: %s', e)  # storage busy or in invalid state
    return False

Prevention

When it happens

Trigger: Triggering a sync while another sync is already IN_PROGRESS; calling info_set_in_progress twice without the status being reset to QUEUED; invoking _scan_and_create_links or save_annotations on a storage whose status is FAILED/COMPLETED after a previous run.

Common situations: Double-clicking the 'Sync Storage' button; a previous sync crashed leaving status stuck at IN_PROGRESS; multiple workers picking up the same storage sync job concurrently.

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


AI-assisted analysis of HumanSignal/label-studio@0b49e9b539 (2026-08-29). Data as JSON: /api/errors/afee0c5e7b262a0d. Report an issue: GitHub.