HumanSignal/label-studio · error · CommandError

Provide --project <id> or --organization <id>

Error message

Provide --project <id> or --organization <id>

What it means

The recalculate_task_counters management command recomputes per-project task/annotation counters. It requires an explicit scope: handle() raises Django's CommandError if neither --project nor --organization is given, preventing an accidentally unbounded recount over all projects.

Source

Thrown at label_studio/tasks/management/commands/recalculate_task_counters.py:60

            help='Only report how many tasks have drifted counters; do not modify anything',
        )

    def _drifted_count(self, project):
        """Number of tasks whose cached total_annotations disagrees with the real count."""
        return (
            Task.objects.filter(project=project)
            .annotate(real_total=Count('annotations', filter=Q(annotations__was_cancelled=False), distinct=True))
            .exclude(total_annotations=F('real_total'))
            .count()
        )

    def handle(self, *args, **options):
        project_id = options.get('project')
        organization_id = options.get('organization')
        dry_run = options.get('dry_run')

        if not project_id and not organization_id:
            raise CommandError('Provide --project <id> or --organization <id>')

        if project_id:
            projects = Project.objects.filter(id=project_id)
            if not projects.exists():
                raise CommandError(f'Project {project_id} not found')
        else:
            projects = Project.objects.filter(organization_id=organization_id)
            if not projects.exists():
                raise CommandError(f'No projects found for organization {organization_id}')

        for project in projects:
            drifted_before = self._drifted_count(project)
            self.stdout.write(
                f'Project {project.id} ({project.title!r}): {drifted_before} task(s) with drifted counters'
            )

            if dry_run:
                continue

View on GitHub (pinned to 0b49e9b539)

Solutions

  1. Run with a project scope: `... recalculate_task_counters --project 12`
  2. Run with an organization scope: `... recalculate_task_counters --organization 1`
  3. Add `--dry_run` first to preview changes before applying
  4. Verify ids exist: wrong ids trigger the follow-up 'Project ... not found' error

Example fix

// before
python label_studio/manage.py recalculate_task_counters
// after
python label_studio/manage.py recalculate_task_counters --project 12 --dry_run
Defensive patterns

Strategy: validation

Validate before calling

# Validate args in a wrapper before invoking the command
import sys
args = sys.argv[1:]
if '--project' not in args and '--organization' not in args:
    sys.exit('Usage: manage.py recalculate_task_counters --project <id> | --organization <id> [--dry_run]')

Type guard

function hasScope(options) { return Boolean(options.project || options.organization); }

Try / catch

from django.core.management import call_command
from django.core.management.base import CommandError
try:
    call_command('recalculate_task_counters', project='12', dry_run=True)
except CommandError as e:
    print(f'Command refused: {e}')  # fix arguments and retry

Prevention

When it happens

Trigger: Running `python label_studio/manage.py recalculate_task_counters` without --project <id> or --organization <id> (with or without --dry_run).

Common situations: Operator forgetting the scope flag when fixing drifted counters; copy-pasting a command example that omitted scope; running via cron with missing arguments.

Understand the failure class

Background: "missing required argument" and "the following required arguments were not provided": what required-argument errors mean and how to fix them — this error's family across 20 libraries.

Related errors


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