{"record":{"id":"9f513c4233517d53","repo":"HumanSignal/label-studio","slug":"can-t-deserialize-tasks-due-to-errors","errorCode":null,"errorMessage":"Can't deserialize tasks due to {errors}","messagePattern":"Can't deserialize tasks due to (.+?)","errorType":"validation","errorClass":"ValidationError","httpStatus":400,"severity":"error","filePath":"label_studio/tasks/serializers.py","lineNumber":558,"sourceCode":"            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:\n                    self.annotation_count += len(item['annotations'])\n                if 'predictions' in item:\n                    self.prediction_count += len(item['predictions'])\n\n        if any(errors):\n            logger.warning(\"Can't deserialize tasks due to \" + str(errors))\n            raise ValidationError(errors)\n\n        return ret\n\n    @staticmethod\n    def _insert_valid_completed_by(annotations, members_email_to_id, members_ids, default_user, ff_user=None):\n        \"\"\"Insert the correct id for completed_by by email/id in annotations.\n\n        Two modes of operation, gated on\n        ``fflag_fix_back_bros_1092_import_unknown_completed_by_short``:\n\n        - FF on (BROS-1092 default): unknown annotators are silently re-attributed\n          to ``default_user`` via :func:`resolve_completed_by_id` so cross-org\n          re-imports do not 400. ``default_user`` here is the importer (when\n          available in serializer context) or ``project.created_by`` as set by\n          :meth:`BaseTaskSerializerBulk.create`.\n        - FF off: keeps the historical strict validation that raises\n          ``ValidationError`` for any value that doesn't resolve to an org member,\n          preserving the legacy behavior for rollback.","sourceCodeStart":540,"sourceCodeEnd":576,"githubUrl":"https://github.com/HumanSignal/label-studio/blob/0b49e9b53917880baf1dd85d574fe5541a9aafb2/label_studio/tasks/serializers.py#L540-L576","documentation":"Raised in BaseTaskSerializerBulk.to_internal_value when one or more task items in an import batch fail per-item validation (self.child.validate / ValidationError). Each failed item is formatted as 'Error... at item i: ...' and the collected list is raised as a single DRF ValidationError after the loop, so the whole import batch is rejected. The library throws it to surface per-task deserialization problems with the offending item echoed for debugging.","triggerScenarios":"POSTing a task import batch (task bulk create API / SDK importer) where at least one item in the JSON list fails the TaskSerializer.validate — e.g. a task missing required data keys, invalid label values, wrong types, or annotations/predictions in an invalid shape.","commonSituations":"Importing a Label Studio export snapshot from a different project/label config; hand-edited JSON with a malformed task; uploading CSV/JSON where one row has null or wrong-typed fields; version drift where a newer export format contains fields the current serializer rejects.","solutions":["Read the 'at item i' messages in the error detail to find the offending tasks and fix the data (the item is echoed inline)","Ensure every task object contains the fields required by the project's labeling config (e.g. a 'data' dict with the configured data key like 'image' or 'text')","Re-export from the source project with the same label config, or update Label Studio so the export format matches the importer","Split the batch and import items individually to isolate the bad records; fix or drop them","Enable logging at WARNING+ to see the full 'Can't deserialize tasks due to [...]' list which may be capped at 100 entries in the response"],"exampleFix":"// before\npayload = [{\"data\": {}}, {\"data\": {\"text\": \"ok\"}}]\nclient.import_tasks(project_id, payload)  # first item fails: missing configured data key\n// after\npayload = [{\"data\": {\"text\": \"hello\"}}, {\"data\": {\"text\": \"ok\"}}]\nclient.import_tasks(project_id, payload)","handlingStrategy":"validation","validationCode":"def validate_import_batch(tasks, required_data_key):\n    errors = []\n    for i, t in enumerate(tasks):\n        if not isinstance(t, dict):\n            errors.append(f'item {i}: not an object')\n            continue\n        data = t.get('data')\n        if not isinstance(data, dict) or required_data_key not in data:\n            errors.append(f'item {i}: data missing key {required_data_key!r}: {t}')\n    if errors:\n        raise ValueError('Invalid task items: ' + '; '.join(errors[:5]))","typeGuard":"def is_valid_task_item(t, required_data_key):\n    return isinstance(t, dict) and isinstance(t.get('data'), dict) and required_data_key in t['data']","tryCatchPattern":"from rest_framework.exceptions import ValidationError\ntry:\n    client.import_tasks(project_id, tasks)\nexcept ValidationError as e:\n    for msg in (e.detail if isinstance(e.detail, list) else [e.detail]):\n        print('Item error:', msg)  # each contains 'at item i:' with the offending payload\n    # fix or drop the flagged items and retry","preventionTips":["Validate each task item against the project's labeling config before import","Keep export source and import target label configs in sync","Test imports with a small batch first","Echo the item index from the error message to locate bad records in large files"],"tags":["django","rest-framework","serialization","import","validation"],"backgroundTag":"task-import-serialization-failed","analyzedSha":"0b49e9b53917880baf1dd85d574fe5541a9aafb2","analyzedAt":"2026-08-29T00:39:52.578Z","schemaVersion":2},"datasetVersion":"2026-08-29T02:17:18.158Z"}