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
- Split the payload into one request per project
- Ensure all items share the same 'project' id in the array
- 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
- Group labels by project before any bulk POST
- Validate payload shape client-side before sending
- Never batch labels across projects in automation
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
- annotation_ser.errors
- Invalid or missing serializer class
- extract_message(exc)
- list should not be empty
- Value must be a list
AI-assisted analysis of HumanSignal/label-studio@0b49e9b539 (2026-08-29).
Data as JSON: /api/errors/51888bf3c70375a3.
Report an issue: GitHub.