{"record":{"id":"ecb0f524c42edd65","repo":"HumanSignal/label-studio","slug":"cannot-start-an-already-completed-task","errorCode":null,"errorMessage":"Cannot start an already completed task","messagePattern":"Cannot start an already completed task","errorType":"validation","errorClass":"TransitionValidationError","httpStatus":null,"severity":"warning","filePath":"label_studio/fsm/transitions.py","lineNumber":110,"sourceCode":"\nclass BaseTransition(BaseModel, ABC, Generic[EntityType, StateModelType]):\n    \"\"\"\n    Abstract base class for all declarative state transitions.\n\n    This provides the framework for implementing transitions as first-class Pydantic\n    models with built-in validation, context handling, and execution logic.\n\n    Example usage:\n        class StartTaskTransition(BaseTransition[Task, TaskState]):\n            assigned_user_id: int = Field(..., description=\"User assigned to start the task\")\n            estimated_duration: Optional[int] = Field(None, description=\"Estimated completion time in hours\")\n\n            def get_target_state(self, context: Optional[TransitionContext[Task, TaskState]]) -> str:\n                return TaskStateChoices.IN_PROGRESS\n\n            def validate_transition(self, context: TransitionContext[Task, TaskState]) -> bool:\n                if context.current_state == TaskStateChoices.COMPLETED:\n                    raise TransitionValidationError(\"Cannot start an already completed task\")\n                return True\n\n            def transition(self, context: TransitionContext[Task, TaskState]) -> Dict[str, Any]:\n                return {\n                    \"assigned_user_id\": self.assigned_user_id,\n                    \"estimated_duration\": self.estimated_duration,\n                    \"started_at\": context.timestamp.isoformat()\n                }\n    \"\"\"\n\n    model_config = ConfigDict(arbitrary_types_allowed=True, validate_assignment=True, use_enum_values=True)\n\n    def __init__(self, **data):\n        super().__init__(**data)\n        self.__context: Optional[TransitionContext[EntityType, StateModelType]] = None\n\n    @property\n    def context(self) -> Optional[TransitionContext[EntityType, StateModelType]]:","sourceCodeStart":92,"sourceCodeEnd":128,"githubUrl":"https://github.com/HumanSignal/label-studio/blob/0b49e9b53917880baf1dd85d574fe5541a9aafb2/label_studio/fsm/transitions.py#L92-L128","documentation":"The example Task 'start' transition's validate_transition raises TransitionValidationError when the task's current state is already COMPLETED. Business rule: a completed task cannot be restarted via the start transition.","triggerScenarios":"Executing the start transition on a Task whose TaskState.current_state == TaskStateChoices.COMPLETED.","commonSituations":"Double-clicking a start/assign button in a UI so the transition fires twice; stale client state re-submitting a start after completion; retry logic replaying an old transition request.","solutions":["Check the task's current state before dispatching the transition; skip if already COMPLETED.","Catch TransitionValidationError and surface 'task already completed' to the user instead of a generic error.","Guard the start transition's target state: use a restart/redo transition for completed tasks if restarting is intended.","Add idempotency handling so duplicate start requests are no-ops."],"exampleFix":"// before\nexecute_transition(task, 'start')\n// after\nif get_current_state(task) != TaskStateChoices.COMPLETED:\n    execute_transition(task, 'start')\nelse:\n    raise TransitionValidationError('Cannot start an already completed task')","handlingStrategy":"validation","validationCode":"current = get_current_state(task)\nif current == TaskStateChoices.COMPLETED:\n    raise TransitionValidationError('Cannot start an already completed task')","typeGuard":"def is_restartable(task) -> bool:\n    return get_current_state(task) != TaskStateChoices.COMPLETED","tryCatchPattern":"try:\n    execute_transition(task, 'start')\nexcept TransitionValidationError:\n    notify_user('This task is already completed and cannot be started again.')","preventionTips":["Disable start actions in the UI when the task is COMPLETED.","Make start requests idempotent (dedupe by task+user).","Refresh entity state before dispatching transitions from stale clients."],"tags":["fsm","state-management","business-rules"],"backgroundTag":"invalid-state-transition","analyzedSha":"0b49e9b53917880baf1dd85d574fe5541a9aafb2","analyzedAt":"2026-08-29T00:39:52.578Z","schemaVersion":2},"datasetVersion":"2026-08-29T02:17:18.158Z"}