HumanSignal/label-studio · error · ValidationError

Creating labels for different projects in one request not al

Error message

Creating labels for different projects in one request not allowed

What it means

DRF ValidationError raised by LabelListSerializer.validate when a bulk label-creation request mixes labels belonging to more than one project. Bulk label creation only supports a single project per request so existing labels can be reused/linked consistently.

Source

Thrown at label_studio/labels_manager/serializers.py:14

from django.conf import settings
from django.db import transaction
from projects.models import Project
from rest_flex_fields import FlexFieldsModelSerializer
from rest_framework import serializers
from rest_framework.exceptions import ValidationError

from .models import Label, LabelLink


class LabelListSerializer(serializers.ListSerializer):
    def validate(self, items):
        if len(set(item['project'] for item in items)) > 1:
            raise ValidationError('Creating labels for different projects in one request not allowed')
        return items

    def create(self, validated_data):
        """Bulk creation objects of Label model with related LabelLink
        reusing already existing labels
        """
        from webhooks.utils import emit_webhooks_for_instance

        with transaction.atomic():
            # loading already existing labels
            titles = [item['title'] for item in validated_data]
            existing_labels = Label.objects.filter(
                organization=self.context['request'].user.active_organization, title__in=titles
            ).all()
            existing_labels_map = {label.title: label for label in existing_labels}

            # create objects for labels, that we need to create
            labels_data = []

View on GitHub (pinned to 0b49e9b539)

Solutions

  1. Split the payload into one request per project
  2. Ensure all items share the same 'project' id in the array
  3. Fix client-side batching logic to group labels by project before POSTing

Example fix

// before
post('/api/labels/', [{"project":1,"value":"A"},{"project":2,"value":"B"}])
// after
post('/api/labels/', [{"project":1,"value":"A"}])
post('/api/labels/', [{"project":2,"value":"B"}])
Defensive patterns

Strategy: validation

Validate before calling

projects = {lbl['project'] for lbl in payload}
assert len(projects) <= 1, 'Batch labels must belong to one project; split per project'

Type guard

def single_project(labels: list[dict]) -> bool:
    return len({lbl.get('project') for lbl in labels}) <= 1

Try / catch

try:
    serializer.is_valid(raise_exception=True)
    serializer.save()
except ValidationError as e:
    if 'different projects' in str(e):
        for project_id, group in groupby(payload, key=lambda l: l['project']):
            post_labels(list(group))

Prevention

When it happens

Trigger: POSTing an array to the labels bulk-create endpoint where the 'project' field differs across items, e.g. [{"project":1,"value":"A"},{"project":2,"value":"B"}].

Common situations: Client scripts looping over multiple projects but batching all labels into one request; UI sending the whole label set without partitioning per project; copy-paste of payloads between projects.

Related errors


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