{"record":{"id":"363368426dac9632","repo":"HumanSignal/label-studio","slug":"required","errorCode":"required","errorMessage":"This field is required.","messagePattern":"This field is required\\.","errorType":"validation","errorClass":"ValidationError","httpStatus":400,"severity":"error","filePath":"label_studio/tasks/serializers.py","lineNumber":392,"sourceCode":"            project = generics.get_object_or_404(Project, kwargs['project_id'])\n        elif task:\n            project = task.project\n        else:\n            project = None\n        return project\n\n    def validate(self, task):\n        instance = self.instance if hasattr(self, 'instance') else None\n\n        project = self.project(task=instance)\n\n        current_request = get_current_request()\n        if current_request and current_request.method == 'POST' and not project:\n            # raise ValidationError for the project field with standard DRF message\n            try:\n                self.fields['project'].fail('required')\n            except ValidationError as exc:\n                raise ValidationError(\n                    {\n                        'project': exc.detail,\n                    }\n                )\n\n        validator = TaskValidator(\n            project,\n            instance=instance if 'data' not in task else None,\n        )\n        return validator.validate(task)\n\n    def create(self, validated_data):\n        # Full-overlap projects skip rearrangement on task add (`_update_tasks_states`\n        # only rearranges when cohort < 100%). Seed overlap like bulk import / storage\n        # sync so is_labeled uses maximum_annotations instead of the model default of 1.\n        # Own this here so both POST /api/tasks/ and POST /api/projects/{id}/tasks/ agree.\n        project = validated_data.get('project') or self.project()\n        if 'overlap' not in validated_data and project is not None and project.overlap_cohort_percentage >= 100:","sourceCodeStart":374,"sourceCodeEnd":410,"githubUrl":"https://github.com/HumanSignal/label-studio/blob/0b49e9b53917880baf1dd85d574fe5541a9aafb2/label_studio/tasks/serializers.py#L374-L410","documentation":"Raised by TaskSerializer.validate when a POST request omits the 'project' field. It uses the standard DRF 'required' field error ('This field is required.') and re-raises it keyed by 'project' so the API response contains a proper per-field error dict.","triggerScenarios":"POST to the task-import endpoints (/api/tasks/ or /api/projects/<id>/tasks/ proxies where the project isn't injected into context) with a payload lacking 'project'. The check only fires for POST requests when project is falsy after context lookup.","commonSituations":"Calling the generic /api/tasks/ endpoint (which requires an explicit project field) instead of the project-scoped /api/projects/<id>/import endpoint; sending tasks via scripts/SDKs without setting project; a proxy or middleware stripping the project key.","solutions":["Add the 'project' field (project id) to your POST payload","Prefer the project-scoped endpoint POST /api/projects/<id>/import or /api/projects/<id>/tasks/ so project comes from the URL","If using the Python SDK, pass project=<id> when creating/uploading tasks","Check that your HTTP client/middleware isn't dropping the project field from the JSON body"],"exampleFix":"// before\nawait fetch('/api/tasks/', { method: 'POST', body: JSON.stringify({ tasks: [{ data: { text: 'x' } }] }) });\n// after\nawait fetch('/api/tasks/', { method: 'POST', body: JSON.stringify({ project: 12, tasks: [{ data: { text: 'x' } }] }) });","handlingStrategy":"validation","validationCode":"// call project-scoped endpoint instead, or verify project is set\nif (!projectId) throw new Error('project id is required for task creation');\nawait fetch(`/api/projects/${projectId}/import/`, { method: 'POST', body: JSON.stringify(tasks) });","typeGuard":"function hasProject(payload) {\n  return typeof payload === 'object' && payload !== null && Number.isInteger(payload.project);\n}","tryCatchPattern":"try {\n  await api.post('/api/tasks/', payload);\n} catch (e) {\n  if (e.response?.data?.project?.[0] === 'This field is required.') {\n    throw new Error('Add project id to payload or use /api/projects/<id>/import/');\n  } throw e;\n}","preventionTips":["Use the project-scoped import endpoint so project comes from the URL","Always include project in task-creation payloads","Unit-test API wrappers to assert required fields before sending"],"tags":["validation","required-field","serializer","drf","tasks"],"backgroundTag":"missing-required-field","analyzedSha":"0b49e9b53917880baf1dd85d574fe5541a9aafb2","analyzedAt":"2026-08-29T00:39:52.578Z","schemaVersion":2},"datasetVersion":"2026-08-29T02:17:18.158Z"}