{"record":{"id":"eaae5dd1b9ac5b06","repo":"HumanSignal/label-studio","slug":"this-task-cannot-be-skipped","errorCode":null,"errorMessage":"This task cannot be skipped.","messagePattern":"This task cannot be skipped\\.","errorType":"validation","errorClass":"ValidationError","httpStatus":400,"severity":"error","filePath":"label_studio/tasks/api.py","lineNumber":1136,"sourceCode":"            # AnnotationDraft#delete has special behavior (updating created_labels_drafts).\n            # This special behavior won't be triggered if we call delete on the queryset.\n            # Only for drafts with empty annotation_id, other ones deleted by signal\n            draft.delete()\n        except AnnotationDraft.DoesNotExist:\n            pass\n\n    def perform_create(self, ser):\n        task = self.parent_object\n        # annotator has write access only to annotations and it can't be checked it after serializer.save()\n        user = self.request.user\n\n        # Check if task is being skipped and if it's allowed\n        was_cancelled_get = bool_from_request(self.request.GET, 'was_cancelled', False)\n        was_cancelled_data = self.request.data.get('was_cancelled', False)\n        is_skipping = was_cancelled_get or was_cancelled_data\n\n        if is_skipping and not task.can_be_skipped():\n            raise ValidationError({'detail': 'This task cannot be skipped.'})\n\n        # updates history\n        result = ser.validated_data.get('result')\n        extra_args = {'task_id': self.kwargs['pk'], 'project_id': task.project_id}\n\n        # save stats about how well annotator annotations coincide with current prediction\n        # only for finished task annotations\n        if result is not None:\n            prediction = Prediction.objects.filter(task=task, model_version=task.project.model_version)\n            if prediction.exists():\n                prediction = prediction.first()\n                prediction_ser = PredictionSerializer(prediction).data\n            else:\n                logger.debug(f'User={self.request.user}: there are no predictions for task={task}')\n                prediction_ser = {}\n            # serialize annotation\n            extra_args.update({'prediction': prediction_ser, 'updated_by': user})\n","sourceCodeStart":1118,"sourceCodeEnd":1154,"githubUrl":"https://github.com/HumanSignal/label-studio/blob/0b49e9b53917880baf1dd85d574fe5541a9aafb2/label_studio/tasks/api.py#L1118-L1154","documentation":"When an annotation is created with was_cancelled=true (i.e. skipping a task), perform_create checks task.can_be_skipped() first. Skipping is only allowed per project annotation settings (e.g. skip enabled for the user's role and within queue/overlap constraints); otherwise a 400 ValidationError with this detail is returned.","triggerScenarios":"POST to the task annotations endpoint with ?was_cancelled=true or body {\"was_cancelled\": true} while the project's annotation settings disallow skipping (skip_type/allow_skip disabled for the role or task state forbids it).","commonSituations":"Annotators pressing 'Skip' in the UI when the project was configured to disallow skips; automation scripts bulk-skipping tasks; overlap fully consumed so no skip slot remains for that user.","solutions":["Enable skipping in Project > Annotation settings (allow skip for the relevant role)","Submit a real annotation instead of a skip (omit was_cancelled)","Reassign the task to a user who is allowed to skip","Adjust `can_be_skipped` conditions (overlap/draft state) if the restriction is unintended"],"exampleFix":"// before (skip attempt)\nPOST /api/tasks/42/annotations/?was_cancelled=true\n// after (enable skip in project settings or submit normally)\nPOST /api/tasks/42/annotations/\n{\"result\": [{\"from_name\": \"label\", \"type\": \"choices\", \"value\": {\"choices\": [\"OK\"]}}]}","handlingStrategy":"validation","validationCode":"// Check skip eligibility client-side before posting a cancelled annotation\nconst settings = await api.get(`/api/projects/${projectId}/`);\nconst skipAllowed = settings.skip_type !== undefined && settings.skip_type !== 'None';\nif (!skipAllowed || !task.can_be_skipped) {\n  // hide/disable the Skip button; do not send was_cancelled=true\n}","typeGuard":"function canSkip(task, projectSettings) {\n  return Boolean(projectSettings.allow_skip) && task.can_be_skipped !== false;\n}","tryCatchPattern":"try {\n  await api.post(`/api/tasks/${taskId}/annotations/?was_cancelled=true`, {});\n} catch (e) {\n  if (e.response?.status === 400 && /cannot be skipped/.test(JSON.stringify(e.response.data))) {\n    // prompt a real annotation instead of retrying the skip\n  } else throw e;\n}","preventionTips":["Configure project skip settings before rollout and communicate them to annotators","Disable the Skip button when project settings disallow it","Avoid automated bulk-skip scripts against projects with skip restrictions","Validate was_cancelled payloads in client code before submission"],"tags":["validation","annotations","business-rule","label-studio"],"backgroundTag":"operation-not-allowed","analyzedSha":"0b49e9b53917880baf1dd85d574fe5541a9aafb2","analyzedAt":"2026-08-29T00:39:52.578Z","schemaVersion":2},"datasetVersion":"2026-08-29T02:17:18.158Z"}