HumanSignal/label-studio · error · ValueError

"file_upload_ids" parameter must be a list of integers

Error message

"file_upload_ids" parameter must be a list of integers

What it means

The FileUpload delete endpoint accepts 'file_upload_ids' in the request body: None deletes ALL uploads for the project, a list deletes only those IDs, and any other type raises this plain ValueError. It is a Python ValueError, not DRF ValidationError, so it typically surfaces as a 500 rather than a structured 400.

Source

Thrown at label_studio/data_import/api.py:863

            return FileUpload.objects.filter(project_id=project.id, user=self.request.user)

        # If requested in regular import, only queried IDs are returned to avoid showing previously imported
        ids = json.loads(self.request.query_params.get('ids', '[]'))
        logger.debug(f'File Upload IDs found: {ids}')
        return FileUpload.objects.filter(project_id=project.id, id__in=ids, user=self.request.user)

    def get(self, request, *args, **kwargs):
        return self.list(request, *args, **kwargs)

    def delete(self, request, *args, **kwargs):
        project = generics.get_object_or_404(Project.objects.for_user(self.request.user), pk=self.kwargs['pk'])
        ids = self.request.data.get('file_upload_ids')
        if ids is None:
            deleted, _ = FileUpload.objects.filter(project=project).delete()
        elif isinstance(ids, list):
            deleted, _ = FileUpload.objects.filter(project=project, id__in=ids).delete()
        else:
            raise ValueError('"file_upload_ids" parameter must be a list of integers')
        return Response({'deleted': deleted}, status=status.HTTP_200_OK)


@method_decorator(
    name='get',
    decorator=extend_schema(
        tags=['Import'],
        summary='Get file upload',
        description='Retrieve details about a specific uploaded file.',
        extensions={
            'x-fern-sdk-group-name': ['files'],
            'x-fern-sdk-method-name': 'get',
            'x-fern-audiences': ['public'],
        },
    ),
)
@method_decorator(
    name='patch',

View on GitHub (pinned to 0b49e9b539)

Solutions

  1. Send file_upload_ids as a JSON array of integers: {"file_upload_ids": [1, 2, 3]}
  2. If deleting a single upload, still wrap it: [42], not 42
  3. If you intended to delete everything, explicitly pass null / omit the key — review carefully, this deletes ALL project uploads
  4. Handle the string case: convert a comma-separated string to a list of ints before sending
  5. Report/handle the 500-style ValueError response in client error handling since it is not a structured 400

Example fix

// before
requests.post(url, headers=headers, json={"file_upload_ids": 42})
// after
requests.post(url, headers=headers, json={"file_upload_ids": [42]})
Defensive patterns

Strategy: type-guard

Validate before calling

ids = body.get('file_upload_ids')
if ids is not None and not (isinstance(ids, list) and all(isinstance(i, int) for i in ids)):
    raise ValueError('file_upload_ids must be a list of integers (or null to delete all)')

Type guard

def is_valid_upload_ids(v) -> bool:
    return v is None or (isinstance(v, list) and all(isinstance(i, int) and not isinstance(i, bool) for i in v))

Try / catch

try:
    resp = requests.post(delete_url, headers=H, json={'file_upload_ids': ids})
    resp.raise_for_status()
except requests.HTTPError as e:
    if 'must be a list of integers' in e.response.text:
        raise TypeError('Wrap the id in a list: {"file_upload_ids": [42]}')

Prevention

When it happens

Trigger: POST/DELETE to the file-upload delete endpoint (api.FileUploadListDelete) with body {'file_upload_ids': <non-list>} — e.g. a single integer 5, a string "5", a dict, or a comma-separated string — instead of a JSON array of integers.

Common situations: Client sending a single ID without wrapping it in a list; form-encoded bodies where lists get serialized as strings; scripts passing a tuple or a set; frontend JSON.stringify mistakes; dangerously sending null/omitting the key and wiping all uploads instead (the None branch is total deletion).

Related errors


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