{"record":{"id":"c6247390ce6859f1","repo":"HumanSignal/label-studio","slug":"empty","errorCode":"empty","errorMessage":"empty","messagePattern":"empty","errorType":"validation","errorClass":"ValidationError","httpStatus":400,"severity":"warning","filePath":"label_studio/tasks/serializers.py","lineNumber":533,"sourceCode":"            code = f' {detail[0].code}' if detail[0].code != 'invalid' else ''\n            return f'Error{code} at item {i}: {detail[0]} :: {item}'\n        else:\n            errors = ', '.join(detail)\n            codes = [d.code for d in detail]\n            return f'Errors {codes} at item {i}: {errors} :: {item}'\n\n    def to_internal_value(self, data):\n        \"\"\"Body of run_validation for all data items\"\"\"\n        if data is None:\n            raise ValidationError('All tasks are empty (None)')\n\n        if not isinstance(data, list):\n            raise ValidationError({api_settings.NON_FIELD_ERRORS_KEY: 'not a list'}, code='not_a_list')\n\n        if not self.allow_empty and len(data) == 0:\n            if self.parent and self.partial:\n                raise SkipField()\n            raise ValidationError({api_settings.NON_FIELD_ERRORS_KEY: 'empty'}, code='empty')\n\n        ret, errors = [], []\n        self.annotation_count, self.prediction_count = 0, 0\n        for i, item in enumerate(data):\n            try:\n                validated = self.child.validate(item)\n            except ValidationError as exc:\n                error = self.format_error(i, exc.detail, item)\n                errors.append(error)\n                # do not print to user too many errors\n                if len(errors) >= 100:\n                    errors[99] = '...'\n                    break\n            else:\n                ret.append(validated)\n                errors.append({})\n\n                if 'annotations' in item:","sourceCodeStart":515,"sourceCodeEnd":551,"githubUrl":"https://github.com/HumanSignal/label-studio/blob/0b49e9b53917880baf1dd85d574fe5541a9aafb2/label_studio/tasks/serializers.py#L515-L551","documentation":"Raised by TaskListSerializer.to_internal_value when the submitted list is empty and allow_empty is False. A POST with an empty array of tasks yields the non-field error 'empty' (code empty); if the serializer is a partial child of a parent serializer, SkipField is raised instead.","triggerScenarios":"POST to /api/projects/<id>/import or /api/tasks/ with a zero-length JSON array ([]) while the serializer disallows empty input.","commonSituations":"Upstream pipeline produced no rows (empty CSV/JSON file); a filter or transformation removed all tasks before submission; re-running an import script after data was already consumed; sync jobs posting deltas that happen to be empty.","solutions":["Only call the import API when you have at least one task; skip the request entirely if the list is empty","Check upstream data extraction (file/CSV/query) for empty results and fail early with a clearer message","If empty imports should be legal for your workflow, relax the empty-data guard before sending or adjust the serializer usage","Add client-side logging to distinguish 'no data fetched' from 'import failed'"],"exampleFix":"// before\nawait fetch(`/api/projects/${id}/import`, { method: 'POST', body: JSON.stringify(tasks) });\n// after\nif (tasks.length === 0) return; // nothing to import\nawait fetch(`/api/projects/${id}/import`, { method: 'POST', body: JSON.stringify(tasks) });","handlingStrategy":"validation","validationCode":"if (Array.isArray(tasks) && tasks.length === 0) {\n  console.info('no tasks to import, skipping API call');\n  return;\n}","typeGuard":"function isNonEmptyTaskList(v) {\n  return Array.isArray(v) && v.length > 0;\n}","tryCatchPattern":"try {\n  await importTasks(projectId, tasks);\n} catch (e) {\n  if (JSON.stringify(e.response?.data || {}).includes('\"empty\"')) {\n    console.warn('Empty task list rejected — check upstream data source');\n  } else throw e;\n}","preventionTips":["Skip the import call when the list is empty instead of sending []","Alert on upstream sources (files, queries) returning zero rows","Distinguish intentional no-op syncs from data-loss regressions with logs/metrics"],"tags":["validation","empty-input","bulk-import","tasks"],"backgroundTag":"empty-payload-rejected","analyzedSha":"0b49e9b53917880baf1dd85d574fe5541a9aafb2","analyzedAt":"2026-08-29T00:39:52.578Z","schemaVersion":2},"datasetVersion":"2026-08-29T02:17:18.158Z"}