HumanSignal/label-studio · error · ValidationError

Field "data" must be string or dict, but not "{type(self.ins

Error message

Field "data" must be string or dict, but not "{type(self.instance.data)}"

What it means

Also in the instance-validation branch of validate(): if Task.instance.data is neither a dict nor a string, this ValidationError fires, embedding the actual Python type name. Task.data is normally a JSONField (dict) or a JSON string; any other stored type indicates a model-level anomaly.

Source

Thrown at label_studio/tasks/validation.py:150

    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:
                raise ValidationError(
                    'Field "data" must be string or dict, but not "' + type(self.instance.data) + '"'
                )
            self.check_data_and_root(self.instance.project, data)
            return task

        # check task is dict
        if not isinstance(task, dict):
            raise ValidationError('Task root must be dict with "data", "meta", "annotations", "predictions" fields')

        # task[data] | task[annotations] | task[predictions] | task[meta]
        if self.check_allowed(task):
            # task[data]
            self.raise_if_wrong_class(task, 'data', (dict, list))
            self.check_data_and_root(self.project, task['data'])

            # task[annotations]: we can't use AnnotationSerializer for validation
            # because it's much different with validation we need here
            self.raise_if_wrong_class(task, 'annotations', list)

View on GitHub (pinned to 0b49e9b539)

Solutions

  1. Normalize task.data to a dict (or JSON string) and save the instance
  2. Inspect the offending task row and correct the column type/content
  3. Check for code paths that assign non-dict/non-str values to task.data
  4. After version upgrades, run a migration/backfill ensuring Task.data is valid JSON dict or string

Example fix

// before
task.data = b'{"text": "hi"}'  # bytes
// after
task.data = json.loads(b'{"text": "hi"}')  # dict
Defensive patterns

Strategy: type-guard

Validate before calling

def data_field_ok(task):
    return isinstance(task.data, (dict, str))
bad = [t.id for t in Task.objects.all() if not data_field_ok(t)]

Type guard

def task_data_is_valid_type(task):
    return hasattr(task, 'data') and isinstance(task.data, (dict, str))

Try / catch

try:
    validator.validate(task)
except ValidationError as e:
    if str(e.detail[0]).startswith('Field "data" must be string or dict'):
        task.data = normalize_to_dict(task.data)
        task.save()

Prevention

When it happens

Trigger: instance.data is e.g. a list stored in a non-JSON field, an int/bytes value from manual DB manipulation, or a custom subclass overriding the data field, reaching validate() during serializer run_validation/to_internal_value.

Common situations: Manual database edits or migrations writing raw Python objects; ORM misuse assigning non-serializable objects to task.data; older Label Studio versions where data was stored differently than the current code expects (version-upgrade artifacts).

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