{"record":{"id":"d1c1f636caed23c0","repo":"HumanSignal/label-studio","slug":"transition-name-transition-is-auto-triggered-and","errorCode":null,"errorMessage":"transition_name: Transition is auto-triggered and cannot be executed manually","messagePattern":"transition_name: Transition is auto-triggered and cannot be executed manually","errorType":"validation","errorClass":"ValidationError","httpStatus":400,"severity":"error","filePath":"label_studio/fsm/api.py","lineNumber":170,"sourceCode":"\n        entity = self.get_entity()\n\n        serializer = self.get_serializer(data=request.data)\n        serializer.is_valid(raise_exception=True)\n        transition_name = serializer.validated_data['transition_name']\n        transition_data = serializer.validated_data.get('transition_data') or {}\n\n        # Validate that transition is registered and manual (not auto-triggered)\n        transition_class = transition_registry.get_transition(entity_name, transition_name)\n        if not transition_class:\n            raise ValidationError({'transition_name': ['Unknown transition for this entity']})\n\n        # If it's a ModelChangeTransition and has any triggers configured, it's not manual\n        if issubclass(transition_class, ModelChangeTransition):\n            triggers_on_create = getattr(transition_class, '_triggers_on_create', False)\n            triggers_on_update = getattr(transition_class, '_triggers_on_update', False)\n            if triggers_on_create or triggers_on_update:\n                raise ValidationError(\n                    {'transition_name': ['Transition is auto-triggered and cannot be executed manually']}\n                )\n\n        # Execute transition\n        StateManager = get_state_manager()\n        try:\n            state_record = StateManager.execute_transition(\n                entity=entity,\n                transition_name=transition_name,\n                transition_data=transition_data,\n                user=request.user,\n                organization_id=getattr(request.user, 'active_organization_id', None),\n            )\n        except PydanticValidationError as e:\n            # Pydantic schema validation errors from transition instantiation\n            raise ValidationError({'detail': extract_message(e)})\n        except TransitionValidationError as e:\n            # Explicit validation failure","sourceCodeStart":152,"sourceCodeEnd":188,"githubUrl":"https://github.com/HumanSignal/label-studio/blob/0b49e9b53917880baf1dd85d574fe5541a9aafb2/label_studio/fsm/api.py#L152-L188","documentation":"This 400 validation error is raised by FSMEntityTransitionAPI.post when the requested transition_name refers to a ModelChangeTransition subclass that has _triggers_on_create or _triggers_on_update set. Such transitions run automatically when the entity model is created or updated, so executing them through the manual transition endpoint would bypass (or duplicate) the automatic trigger. The FSM API refuses to invoke auto-triggered transitions by name via POST /api/fsm/entities/{entity_type}/{entity_id}/transition/.","triggerScenarios":"POSTing to the FSM transition endpoint with a transition_name that resolves (via transition_registry.get_transition) to a ModelChangeTransition subclass whose _triggers_on_create or _triggers_on_update flag is True. Typically a client copies a transition name from the registry/code that is meant to fire from the model save path, not from the API.","commonSituations":"Automations that build transition calls from a registry listing all transitions without filtering auto-triggered ones; docs/SDK examples that show a transition name registered for model-save triggering; a transition class where someone later added on_create/on_update triggers, breaking previously-working manual API calls.","solutions":["Remove this transition_name from the manual API call; let the transition fire automatically on entity create/update instead.","If a manual variant is needed, register a separate plain Transition (not a ModelChangeTransition with triggers) and call that name from the API.","Check the transition class for _triggers_on_create/_triggers_on_update (set via trigger decorators/settings) and remove those triggers if the transition should truly be manual-only.","Filter the registry listing used to build client UIs so auto-triggered transitions are not offered for manual execution."],"exampleFix":"// before\nPOST /api/fsm/entities/task/123/transition/\n{\"transition_name\": \"task_updated_on_draft_unsaved\"}  // auto-triggered on update\n\n// after\n// don't call it manually; update the entity and let the trigger fire:\nTask.objects.filter(id=123).update(...)  // ModelChangeTransition fires automatically\n// or register a manual-only transition and call it:\n{\"transition_name\": \"manually_approve_task\"}","handlingStrategy":"validation","validationCode":"from fsm.registry import transition_registry\nfrom fsm.transitions import ModelChangeTransition\n\ntc = transition_registry.get_transition(entity_name, transition_name)\nmanual_ok = tc is not None and not (\n    issubclass(tc, ModelChangeTransition)\n    and (getattr(tc, '_triggers_on_create', False) or getattr(tc, '_triggers_on_update', False))\n)\nif not manual_ok:\n    raise ValueError(f'{transition_name} is not manually executable')","typeGuard":"def is_manual_transition(transition_class) -> bool:\n    from fsm.transitions import ModelChangeTransition\n    if transition_class is None or not issubclass(transition_class, ModelChangeTransition):\n        return transition_class is not None\n    return not (getattr(transition_class, '_triggers_on_create', False) or getattr(transition_class, '_triggers_on_update', False))","tryCatchPattern":"from rest_framework.exceptions import ValidationError\ntry:\n    resp = client.post(f'/api/fsm/entities/{entity_type}/{entity_id}/transition/', payload)\nexcept Exception as e:\n    if 'auto-triggered and cannot be executed manually' in str(e):\n        logger.info('transition %s is auto-triggered; skipping manual call', transition_name)\n    else:\n        raise","preventionTips":["List only manual transitions in UIs/clients by filtering out ModelChangeTransition subclasses with triggers","Never call auto-triggered transitions by name from API clients","Grep transition classes for _triggers_on_create/_triggers_on_update before wiring manual calls"],"tags":["api","validation","fsm","transition"],"backgroundTag":"auto-triggered-transition-not-manual","analyzedSha":"0b49e9b53917880baf1dd85d574fe5541a9aafb2","analyzedAt":"2026-08-29T00:39:52.578Z","schemaVersion":2},"datasetVersion":"2026-08-29T02:17:18.158Z"}