HumanSignal/label-studio · error · ValidationError

Task is empty (None)

Error message

Task is empty (None)

What it means

TaskValidator.check_data raises this DRF ValidationError when the task's data payload is literally None. Label Studio requires every task to carry a data dict containing the fields named by the project's labeling config (e.g. the $text variable's key), so a None payload cannot possibly satisfy any config. It is the first guard in check_data, before config-driven key/type checks run.

Source

Thrown at label_studio/tasks/validation.py:58

    'Ranker': [list, str],
}
logger = logging.getLogger(__name__)


class TaskValidator:
    """Task Validator with project scheme configs validation. It is equal to TaskSerializer from django backend."""

    def __init__(self, project, instance=None):
        self.project = project
        self.instance = instance
        self.annotation_count = 0
        self.prediction_count = 0

    @staticmethod
    def check_data(project, data):
        """Validate data from task['data']"""
        if data is None:
            raise ValidationError('Task is empty (None)')

        replace_task_data_undefined_with_config_field(data, project)

        # iterate over data types from project
        for data_key, data_type in project.data_types.items():
            # get array name in case of Repeater tag
            is_array = '[' in data_key
            data_key = data_key.split('[')[0]

            if '.' in data_key:
                keys = data_key.split('.')
                try:
                    data_item = reduce(getitem, keys, data)
                except KeyError:
                    raise ValidationError('"{data_key}" key is expected in task data'.format(data_key=data_key))
            else:
                if data_key not in data:
                    raise ValidationError('"{data_key}" key is expected in task data'.format(data_key=data_key))

View on GitHub (pinned to 0b49e9b539)

Solutions

  1. Replace None data with a dict containing the required config keys, e.g. {'text': ...}
  2. Filter out null items from the import batch before calling the import/tasks API
  3. If a record is genuinely empty, skip it server-side rather than submitting it
  4. Catch ValidationError and report the offending item index to the user

Example fix

// before
client.start_project(label_config=config).import_tasks([{'data': None}])
// after
client.start_project(label_config=config).import_tasks([{'data': {'text': row.get('text', '')}} if row else {'data': {'text': ''}}])
Defensive patterns

Strategy: validation

Validate before calling

def ensure_task_data(items):
    bad = [i for i, t in enumerate(items) if t is None or t.get('data') is None]
    if bad:
        raise ValueError(f'items at {bad} have None data')

Type guard

def has_data(item):
    return isinstance(item, dict) and item.get('data') is not None

Try / catch

from rest_framework.exceptions import ValidationError
try:
    validator.validate(item)
except ValidationError as e:
    if 'Task is empty' in str(e.detail[0]):
        log.warning('skipping null task item')

Prevention

When it happens

Trigger: POST/IMPORT of a task item whose 'data' value is None (e.g. {'data': None} in the tasks list, or an item that is None and gets routed through validate -> check_data_and_root -> check_data).

Common situations: Import scripts building tasks from rows where a source record is null; JSON imports where a line is the literal 'null'; CSV/pandas pipelines where missing rows become None instead of {}; SDK calls passing data=None.

Related errors


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