{"record":{"id":"6f740451d194c77b","repo":"HumanSignal/label-studio","slug":"project-is-required-for-prediction-validation","errorCode":null,"errorMessage":"Project is required for prediction validation","messagePattern":"Project is required for prediction validation","errorType":"validation","errorClass":"ValidationError","httpStatus":400,"severity":"error","filePath":"label_studio/tasks/serializers.py","lineNumber":112,"sourceCode":"        'select specific model version for showing preannotations in the labeling interface',\n    )\n    created_ago = serializers.CharField(default='', read_only=True, help_text='Delta time from creation time')\n\n    def validate(self, data):\n        \"\"\"Validate prediction using LabelInterface against project configuration\"\"\"\n        project = None\n        if 'task' in data:\n            project = data['task'].project\n        elif 'project' in data:\n            project = data['project']\n        ff_user = project.organization.created_by if project else 'auto'\n\n        # Only validate if we're updating the result field\n        if 'result' not in data:\n            return data\n\n        if not project:\n            raise ValidationError('Project is required for prediction validation')\n\n        custom_interface_validator = load_func(getattr(settings, 'CUSTOM_INTERFACE_PREDICTION_VALIDATOR', None))\n        if custom_interface_validator:\n            validation_errors = custom_interface_validator(project, data.get('result', []))\n            if validation_errors:\n                raise ValidationError(f'Error validating prediction: {validation_errors}')\n\n        if not flag_set('fflag_feat_utc_210_prediction_validation_15082025', user=ff_user):\n            # Skip validation if feature flag is not set\n            logger.info(f'Skipping prediction validation in PredictionSerializer for user {ff_user}')\n            return super().validate(data)\n\n        # Custom Interface projects normally keep the default <View></View>\n        # label_config and are validated above against output_schema instead.\n        if not project.label_config_is_not_default:\n            return super().validate(data)\n\n        # Validate prediction using LabelInterface","sourceCodeStart":94,"sourceCodeEnd":130,"githubUrl":"https://github.com/HumanSignal/label-studio/blob/0b49e9b53917880baf1dd85d574fe5541a9aafb2/label_studio/tasks/serializers.py#L94-L130","documentation":"PredictionSerializer.validate() validates the prediction's result against the project's labeling configuration, which requires resolving the related Project from data['task'].project or data['project']. When the payload updates 'result' but contains neither a task nor a project, the validator raises ValidationError because it has no label config to validate against.","triggerScenarios":"PATCH/PUT to the predictions API updating only the result field without including task (e.g. no task PK in the request, or task not passed in serializer context) so neither data['task'] nor data['project'] is present.","commonSituations":"Client scripts PATCHing /api/predictions/<id>/ with only {\"result\": [...]}; bulk update utilities that drop task from the payload; custom code using the serializer directly with partial data and an empty context.","solutions":["Include the task (or project) in the request payload, e.g. PATCH {\"task\": <task_id>, \"result\": [...]}\n","Pass the existing prediction's task via serializer context or instance so project can be resolved (self.instance.project is used in AnnotationSerializer; ensure PredictionSerializer is called with the instance)","If updating standalone, first fetch the prediction and supply project= prediction.task.project in serializer data/context"],"exampleFix":"// before\nrequests.patch(f\"/api/predictions/{pid}/\", json={\"result\": result})\n// after\nrequests.patch(f\"/api/predictions/{pid}/\", json={\"task\": task_id, \"result\": result})","handlingStrategy":"validation","validationCode":"def assert_payload_has_project(payload):\n    if 'result' in payload and 'task' not in payload and 'project' not in payload:\n        raise ValueError(\"updating 'result' requires 'task' or 'project' in the payload for validation\")","typeGuard":"def can_validate_prediction(data: dict) -> bool:\n    return ('result' not in data) or ('task' in data or 'project' in data)","tryCatchPattern":"from rest_framework.exceptions import ValidationError\ntry:\n    ser = PredictionSerializer(instance=prediction, data={\"result\": result}, partial=True)\n    ser.is_valid(raise_exception=True)\nexcept ValidationError as e:\n    logger.error(\"prediction update rejected: %s\", e)  # likely missing task/project","preventionTips":["Always include task (or project) when PATCHing prediction results","When using the serializer directly, supply the instance so the project can be resolved via context/instance","Never build partial prediction payloads that drop the task FK","In bulk-update scripts, fetch each prediction and pass its task_id along with the new result"],"tags":["serializer","prediction","validation","missing-field"],"backgroundTag":"missing-required-field","analyzedSha":"0b49e9b53917880baf1dd85d574fe5541a9aafb2","analyzedAt":"2026-08-29T00:39:52.578Z","schemaVersion":2},"datasetVersion":"2026-08-29T02:17:18.158Z"}