HumanSignal/label-studio · warning · ValidationError
Conversion to {export_type} already started
Error message
Conversion to {export_type} already started What it means
The convert endpoint post() uses get_or_create on ConvertedFormat excluding FAILED records; if a matching non-failed ConvertedFormat already exists (created == False), a conversion for that export_type was already started or completed, so it raises ValidationError 'Conversion to {export_type} already started' to prevent duplicate jobs.
Source
Thrown at label_studio/data_export/api.py:703
)
class ExportConvertAPI(generics.CreateAPIView):
queryset = Export.objects.all()
lookup_url_kwarg = 'export_pk'
permission_required = all_permissions.projects_change
def post(self, request, *args, **kwargs):
snapshot = self.get_object()
serializer = ExportConvertSerializer(data=request.data, context={'project': snapshot.project})
serializer.is_valid(raise_exception=True)
export_type = serializer.validated_data['export_type']
download_resources = serializer.validated_data.get('download_resources')
converted_format, created = ConvertedFormat.objects.exclude(
status=ConvertedFormat.Status.FAILED
).get_or_create(export=snapshot, export_type=export_type)
if not created:
raise ValidationError(f'Conversion to {export_type} already started')
start_job_async_or_sync(
async_convert,
converted_format.id,
export_type,
snapshot.project,
request.build_absolute_uri('/'),
download_resources=download_resources,
on_failure=set_convert_background_failure,
)
return Response({'export_type': export_type, 'converted_format': converted_format.id})
View on GitHub (pinned to 0b49e9b539)
Solutions
- Don't re-POST; poll the existing ConvertedFormat status until it completes, then download via GET ?export_type=<type>.
- Treat this as idempotent: catch the error and just proceed to poll/download.
- If a job is stuck IN_PROGRESS indefinitely, have an admin reset/delete the ConvertedFormat row (or the FAILED ones are auto-retriable by design) and re-POST.
- Add client-side disable/dedupe on the convert button while a job is pending.
Example fix
// before (duplicate request) POST /api/projects/1/exports/abc/convert -> 400 already started POST /api/projects/1/exports/abc/convert -> 400 already started // after POST /api/projects/1/exports/abc/convert (once) GET /api/projects/1/exports/abc?export_type=CSV (poll until ready)
Defensive patterns
Strategy: try-catch
Validate before calling
def conversion_pending(snapshot, export_type):
return snapshot.converted_formats.exclude(status='failed').filter(
export_type=export_type
).exists() Try / catch
try:
trigger_conversion(snapshot_id, export_type)
except ValidationError as e:
if 'already started' in str(e):
pass # idempotent: existing job will finish; go poll status
else:
raise
wait_for_conversion(snapshot_id, export_type) Prevention
- Check existing ConvertedFormat status before POSTing conversion
- Disable convert buttons client-side while a job is pending
- Treat 'already started' as success and proceed to polling/download
- If a job is stuck IN_PROGRESS, clean up the row before retrying
When it happens
Trigger: POSTing the convert request twice for the same export snapshot and export_type (CSV twice), or after a previous conversion is still IN_PROGRESS or already COMPLETED.
Common situations: Users double-clicking the export-convert button; clients retrying with unclear feedback; an earlier conversion succeeded so a new one is unnecessary; a previous job stuck IN_PROGRESS blocking retries without cleanup.
Related errors
- {export_type} format is not converted yet
- No converted file found, probably there are no annotations i
AI-assisted analysis of HumanSignal/label-studio@0b49e9b539 (2026-08-29).
Data as JSON: /api/errors/0dea5e8471bebbdc.
Report an issue: GitHub.