HumanSignal/label-studio · error · ValidationError

Task[{key}] must be {class_def}

Error message

Task[{key}] must be {class_def}

What it means

TaskValidator.raise_if_wrong_class enforces that optional task-root fields have specific Python types: 'data' must be dict or list, 'annotations' a list, 'predictions' a list, 'meta' a dict or list. If the key is present with the wrong type, this ValidationError names the required class (joined with ' or ' for tuples).

Source

Thrown at label_studio/tasks/validation.py:131

                raise ValidationError(e.detail[0] + ' [assume: item["data"] = task root with values]')

    @staticmethod
    def check_allowed(task):
        # task is required
        if 'data' not in task:
            return False

        # everything is ok
        return True

    @staticmethod
    def raise_if_wrong_class(task, key, class_def):
        if key in task and not isinstance(task[key], class_def):
            if isinstance(class_def, tuple):
                class_def = ' or '.join([c.__name__ for c in class_def])
            else:
                class_def = class_def.__name__
            raise ValidationError('Task[{key}] must be {class_def}'.format(key=key, class_def=class_def))

    def validate(self, task):
        """Validate whole task with task['data'] and task['annotations']. task['predictions']"""
        # task is class
        if hasattr(task, 'data'):
            self.check_data_and_root(self.project, task.data)
            return task

        # self.instance is loaded by get_object of view
        if self.instance and hasattr(self.instance, 'data'):
            if isinstance(self.instance.data, dict):
                data = self.instance.data
            elif isinstance(self.instance.data, str):
                try:
                    data = json.loads(self.instance.data)
                except ValueError as e:
                    raise ValidationError("Can't parse task data: " + extract_message(e))
            else:

View on GitHub (pinned to 0b49e9b539)

Solutions

  1. Ensure task['data'] is a dict (or list), task['annotations'] and task['predictions'] are lists, task['meta'] is a dict or list
  2. Parse stringified JSON before submission (json.loads the data string) so 'data' is a real dict
  3. Move a single annotation/prediction into a one-element list: [prediction]
  4. Pre-validate the task root shape before calling the API

Example fix

// before
{'data': '{"text": "hi"}', 'predictions': {'result': []}}
// after
{'data': {'text': 'hi'}, 'predictions': [{'result': []}]}
Defensive patterns

Strategy: type-guard

Validate before calling

def check_root_shape(task):
    assert 'data' not in task or isinstance(task['data'], (dict, list))
    assert 'annotations' not in task or isinstance(task['annotations'], list)
    assert 'predictions' not in task or isinstance(task['predictions'], list)
    assert 'meta' not in task or isinstance(task['meta'], (dict, list))

Type guard

def task_root_ok(task):
    return (isinstance(task, dict)
            and (not isinstance(task.get('data'), str))
            and isinstance(task.get('annotations', []), list)
            and isinstance(task.get('predictions', []), list))

Try / catch

try:
    import_tasks(tasks)
except ValidationError as e:
    m = re.search(r'Task\[(\w+)\] must be ([\w or ]+)', str(e.detail[0]))
    if m:
        coerce_task_field(tasks, m.group(1), m.group(2))

Prevention

When it happens

Trigger: validate() calling raise_if_wrong_class with e.g. {'data': 'not-a-dict'}, {'annotations': {'result': []}} (dict instead of list), or {'predictions': 'pending'}.

Common situations: Putting pre-annotations under 'annotations' as a dict instead of a list of annotation objects; string-encoded JSON left in 'data' instead of a parsed dict; sending 'predictions' as a single object rather than an array.

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/eb208297570b41d4. Report an issue: GitHub.