{"record":{"id":"79937e2a597f1a8d","repo":"HumanSignal/label-studio","slug":"annotation-must-have-result-fields","errorCode":null,"errorMessage":"Annotation must have \"result\" fields","messagePattern":"Annotation must have \"result\" fields","errorType":"validation","errorClass":"ValidationError","httpStatus":400,"severity":"error","filePath":"label_studio/tasks/validation.py","lineNumber":176,"sourceCode":"            raise ValidationError('Task root must be dict with \"data\", \"meta\", \"annotations\", \"predictions\" fields')\n\n        # task[data] | task[annotations] | task[predictions] | task[meta]\n        if self.check_allowed(task):\n            # task[data]\n            self.raise_if_wrong_class(task, 'data', (dict, list))\n            self.check_data_and_root(self.project, task['data'])\n\n            # task[annotations]: we can't use AnnotationSerializer for validation\n            # because it's much different with validation we need here\n            self.raise_if_wrong_class(task, 'annotations', list)\n            for annotation in task.get('annotations', []):\n                if not isinstance(annotation, dict):\n                    logger.warning('Annotation must be dict, but \"%s\" found', str(type(annotation)))\n                    continue\n\n                ok = 'result' in annotation\n                if not ok:\n                    raise ValidationError('Annotation must have \"result\" fields')\n\n                # check result is list\n                if not isinstance(annotation.get('result', []), list):\n                    raise ValidationError('\"result\" field in annotation must be list')\n\n            # task[predictions]\n            self.raise_if_wrong_class(task, 'predictions', list)\n            for prediction in task.get('predictions', []):\n                if not isinstance(prediction, dict):\n                    logger.warning('Prediction must be dict, but \"%s\" found', str(type(prediction)))\n                    continue\n\n                ok = 'result' in prediction\n                if not ok:\n                    raise ValidationError('Prediction must have \"result\" fields')\n\n            # task[meta]\n            self.raise_if_wrong_class(task, 'meta', (dict, list))","sourceCodeStart":158,"sourceCodeEnd":194,"githubUrl":"https://github.com/HumanSignal/label-studio/blob/0b49e9b53917880baf1dd85d574fe5541a9aafb2/label_studio/tasks/validation.py#L158-L194","documentation":"TaskValidator.validate in label_studio/tasks/validation.py raises this DRF ValidationError when a task item's 'annotations' list contains a dict entry that has no 'result' key. Label Studio's task import format requires every annotation to carry a 'result' array holding the labeling results, so an annotation without it is considered malformed and the whole import batch is rejected.","triggerScenarios":"POSTing tasks to the task import API (e.g. /api/projects/<id>/import) with an item like {'data': {...}, 'annotations': [{'completed_by': 1}]} — an annotation dict present but missing 'result'. Only annotation entries that are dicts trigger this; non-dict entries are skipped with a warning.","commonSituations":"Scripts exporting annotations from other tools (or older Label Studio exports) that omit 'result'; hand-written import JSON where only annotations metadata (lead_time, completed_by) was copied; API clients building annotations programmatically and forgetting the results array.","solutions":["Add a 'result' key with a list value to every annotation dict, e.g. 'result': [] for a no-op annotation","If the annotation has no labeling results, import it without the 'annotations' key entirely","Validate the import JSON locally before POSTing: for each task, for each a in task.get('annotations', []): assert isinstance(a.get('result'), list)","Remove pre-annotations/annotations from the payload if you only intend to import raw task data"],"exampleFix":"// before\n{\"data\": {\"text\": \"hi\"}, \"annotations\": [{\"completed_by\": 1}]}\n// after\n{\"data\": {\"text\": \"hi\"}, \"annotations\": [{\"completed_by\": 1, \"result\": []}]}","handlingStrategy":"validation","validationCode":"def validate_annotations(task):\n    for a in task.get('annotations', []):\n        if isinstance(a, dict) and 'result' not in a:\n            raise ValueError('annotation missing result: %r' % a)\n        if isinstance(a, dict) and not isinstance(a['result'], list):\n            raise ValueError('annotation result must be a list')","typeGuard":"def has_valid_annotation(a):\n    return isinstance(a, dict) and isinstance(a.get('result'), list)","tryCatchPattern":"try:\n    client.import_tasks(id=project_id, tasks=tasks)\nexcept LabelStudioError as e:\n    if 'Annotation must have \"result\" fields' in str(e):\n        tasks = [fix_annotation(t) for t in tasks]\n        client.import_tasks(id=project_id, tasks=tasks)\n    else:\n        raise","preventionTips":["Always include 'result': [] in annotation dicts, even when empty","Never copy annotation metadata from foreign tools without adding a result array","Run a local schema check on annotations before import","Drop the 'annotations' key entirely if you have no annotation results"],"tags":["validation","task-import","annotations","rest-api"],"backgroundTag":"missing-required-field","analyzedSha":"0b49e9b53917880baf1dd85d574fe5541a9aafb2","analyzedAt":"2026-08-29T00:39:52.578Z","schemaVersion":2},"datasetVersion":"2026-08-29T02:17:18.158Z"}