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
- Normalize task.data to a dict (or JSON string) and save the instance
- Inspect the offending task row and correct the column type/content
- Check for code paths that assign non-dict/non-str values to task.data
- 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
- Never assign raw Python objects/bytes to task.data; assign dicts
- Guard ORM writes: assert isinstance(value, (dict, str)) before task.data = value
- After migrations/upgrades, sweep Task rows for non-dict/non-str data values
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
- Task[{key}] must be {class_def}
- Task root must be dict with "data", "meta", "annotations", "
- Error getting current state: {e}
- Failed to transition state: {e}
- Database error during project creation. Try again.
AI-assisted analysis of HumanSignal/label-studio@0b49e9b539 (2026-08-29).
Data as JSON: /api/errors/21b85fb596efb18b.
Report an issue: GitHub.