HumanSignal/label-studio · warning · ValidationError

{e.detail[0]} [assume: item as is = task root with values]

Error message

{e.detail[0]} [assume: item as is = task root with values] 

What it means

check_data_and_root wraps check_data: when the inner validation fails and dict_is_root=True, it re-raises the original message plus the hint " [assume: item as is = task root with values] ". This variant fires when the submitted item had NO 'data' field, so Label Studio treated the item itself as the data payload (validate()'s else-branch calls check_data_and_root(project, task, dict_is_root=True)), and that data also failed validation.

Source

Thrown at label_studio/tasks/validation.py:111

                    )
                )

        return data

    @staticmethod
    def check_data_and_root(project, data, dict_is_root=False):
        """Check data consistent and data is dict with task or dict['task'] is task

        :param project:
        :param data:
        :param dict_is_root:
        :return:
        """
        try:
            TaskValidator.check_data(project, data)
        except ValidationError as e:
            if dict_is_root:
                raise ValidationError(e.detail[0] + ' [assume: item as is = task root with values] ')
            else:
                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:

View on GitHub (pinned to 0b49e9b539)

Solutions

  1. Read the prefix of the message (the e.detail[0] part) to find the real validation failure, then fix that in the item
  2. Prefer wrapping payloads explicitly: {'data': {...}} so the root-assumption path is never taken
  3. Ensure the unwrapped item's keys match the config variables and their expected types
  4. Normalize the whole batch to one shape (all wrapped or all bare data dicts) before import

Example fix

// before
import_tasks([{'text': 123}])  # config <Text value="$text"/> but Text won't accept... wait, 123 is fine; e.g. {'img': {'url': 'x'}}
// after
import_tasks([{'data': {'img': 'x'}}])  # or fix the inner failure indicated before the hint
Defensive patterns

Strategy: validation

Validate before calling

def is_wrapped(item):
    return isinstance(item, dict) and 'data' in item
bad = [i for i, t in enumerate(items) if not is_wrapped(t)]
if bad:
    items = [{'data': t} if isinstance(t, dict) else {'data': {}} for t in items]

Type guard

def is_bare_data_dict(item):
    return isinstance(item, dict) and 'data' not in item

Try / catch

try:
    import_tasks(items)
except ValidationError as e:
    msg = str(e.detail[0])
    if 'item as is = task root' in msg:
        items = [{'data': it} for it in items]  # switch to explicit wrapping
        import_tasks(items)

Prevention

When it happens

Trigger: Importing an item like {'text': 'hello'} (no 'data' key) where 'text' itself fails check_data (missing required config key, wrong type, etc.); validate() falls to the else-branch and validates the item as data with dict_is_root=True.

Common situations: Bulk imports that submit raw data dicts without wrapping in {'data': ...}; users assuming top-level keys like annotations/predictions can sit beside unwrapped data; mixed batches where some items are wrapped and some are not.

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