HumanSignal/label-studio · error · ValidationError

detail: {pydantic validation message}

Error message

detail: {pydantic validation message}

What it means

When FSMEntityTransitionAPI.post executes a transition, the transition's payload is instantiated against a pydantic schema. If that instantiation raises pydantic's ValidationError, the API converts it into a DRF 400 ValidationError with the message extracted by extract_message. This is a request-payload shape/type failure for the transition_data you supplied, not an internal failure.

Source

Thrown at label_studio/fsm/api.py:186

            triggers_on_update = getattr(transition_class, '_triggers_on_update', False)
            if triggers_on_create or triggers_on_update:
                raise ValidationError(
                    {'transition_name': ['Transition is auto-triggered and cannot be executed manually']}
                )

        # Execute transition
        StateManager = get_state_manager()
        try:
            state_record = StateManager.execute_transition(
                entity=entity,
                transition_name=transition_name,
                transition_data=transition_data,
                user=request.user,
                organization_id=getattr(request.user, 'active_organization_id', None),
            )
        except PydanticValidationError as e:
            # Pydantic schema validation errors from transition instantiation
            raise ValidationError({'detail': extract_message(e)})
        except TransitionValidationError as e:
            # Explicit validation failure
            logger.warning(
                f'Transition validation failed with context: {e.context} and error: {e} for entity: {entity.id}'
            )
            raise ValidationError({'detail': extract_message(e)})
        # Handle feature-flag disabled path (no state record created)
        if state_record is None:
            response_payload = {
                'success': True,
                'new_state': None,
                'state_record': None,
            }
        else:
            response_payload = {
                'success': True,
                'new_state': state_record.state,
                # Pass model instance; nested serializer will handle representation

View on GitHub (pinned to 0b49e9b539)

Solutions

  1. Read the returned pydantic message and fix transition_data to match the transition's pydantic schema (correct keys, types, required fields).
  2. Inspect the transition class's pydantic model in the code to see the exact expected payload shape.
  3. Validate the payload client-side with the same pydantic model (or its JSON schema) before calling the API.
  4. Check for a version mismatch where the deployed transition schema is newer than the client; update the client payload accordingly.

Example fix

// before (400: 'transition_data.comment: field required')
{"transition_name": "reject_annotation", "transition_data": {"reason": "bad"}}

// after
{"transition_name": "reject_annotation", "transition_data": {"comment": "bad label", "reason": "bad"}}
Defensive patterns

Strategy: validation

Validate before calling

from fsm.registry import transition_registry

transition_class = transition_registry.get_transition(entity_name, transition_name)
validated = transition_class.InputSchema(**transition_data)  # raises locally, same message pydantic would give
payload = {'transition_name': transition_name, 'transition_data': validated.model_dump()}

Type guard

def has_valid_transition_data(transition_class, transition_data: dict) -> bool:
    schema = getattr(transition_class, 'InputSchema', None) or getattr(transition_class, 'input_schema', None)
    if schema is None:
        return True
    try:
        schema(**transition_data)
        return True
    except Exception:
        return False

Try / catch

try:
    resp = client.execute_transition(entity_type, entity_id, transition_name, transition_data)
except Exception as e:
    if 'detail' in str(e):  # pydantic message surfaced by the API
        logger.error('invalid transition_data for %s: %s', transition_name, e)
    raise

Prevention

When it happens

Trigger: POSTing to the FSM transition endpoint where transition_data does not match the transition class's pydantic input schema: missing required fields, wrong types, extra fields when extra="forbid", or values failing field constraints.

Common situations: Sending flat fields instead of the nested transition_data object; passing string values where pydantic expects int/enum; after upgrading, the transition schema gained a new required field that older clients don't send; typos in transition_data keys.

Understand the failure class

Background: Schema validation failed / invalid input schema: payload rejected because its shape doesn't match the expected schema — this error's family across 28 libraries.

Related errors


AI-assisted analysis of HumanSignal/label-studio@0b49e9b539 (2026-08-29). Data as JSON: /api/errors/d12389b345deefdb. Report an issue: GitHub.