HumanSignal/label-studio · error · ValidationError

Each item in prediction result should be dict

Error message

Each item in prediction result should be dict

What it means

Prediction.prepare_prediction_result() accepts the prediction result either as a full list representation or as a dict ('value' style). When a list is given, every element must be a dict (a region object with id/from_name/type/value etc.). If any element is a scalar, string, or list, ValidationError is raised because the result shape is invalid.

Source

Thrown at label_studio/tasks/models.py:1126

        return timesince(self.created_at)

    def has_permission(self, user):
        user.project = self.project  # link for activity log
        return self.project.has_permission(user)

    @classmethod
    def prepare_prediction_result(cls, result, project):
        """
        This function does the following logic of transforming "result" object:
        result is list -> use raw result as is
        result is dict -> put result under single "value" section
        result is string -> find first occurrence of single-valued tag (Choices, TextArea, etc.) and put string under corresponding single field (e.g. "choices": ["my_label"])  # noqa
        """
        if isinstance(result, list):
            # full representation of result
            for item in result:
                if not isinstance(item, dict):
                    raise ValidationError('Each item in prediction result should be dict')
            # TODO: check consistency with project.label_config
            return result

        elif isinstance(result, dict):
            # "value" from result
            # TODO: validate value fields according to project.label_config
            for tag, tag_info in project.get_parsed_config().items():
                tag_type = tag_info['type'].lower()
                if tag_type in result:
                    return [
                        {
                            'from_name': tag,
                            'to_name': ','.join(tag_info['to_name']),
                            'type': tag_type,
                            'value': result,
                        }
                    ]

View on GitHub (pinned to 0b49e9b539)

Solutions

  1. Wrap each item as a full result dict: {"id": <unique>, "from_name": <control tag name>, "to_name": <source>, "type": <tag type>, "value": {...}}
  2. If you only have a single value (e.g. one label string), pass result as a plain string/dict instead of a list and let prepare_prediction_result build the region
  3. Validate client-side before sending: all(isinstance(item, dict) for item in result)
  4. Inspect what your model backend returns and convert its output to Label Studio prediction format in a wrapper

Example fix

// before
Prediction.objects.create(task=task, result=["cat", "dog"])
// after
Prediction.objects.create(task=task, result=[
    {"id": 1, "from_name": "label", "to_name": "image", "type": "choices", "value": {"choices": ["cat"]}}
])
Defensive patterns

Strategy: type-guard

Validate before calling

def validate_prediction_result(result):
    if isinstance(result, list):
        bad = [i for i, item in enumerate(result) if not isinstance(item, dict)]
        if bad:
            raise ValueError(f"result items at indexes {bad} must be dicts")
    return result

Type guard

def is_full_result_format(result) -> bool:
    return isinstance(result, list) and all(isinstance(item, dict) for item in result)

Try / catch

from rest_framework.exceptions import ValidationError
try:
    prediction = Prediction.objects.create(task=task, result=raw_output)
except ValidationError as e:
    logger.error("invalid prediction result %r: %s", raw_output, e)
    prediction = None  # convert backend output to LS format and retry

Prevention

When it happens

Trigger: Calling Prediction.objects.create(...), task.add_predictions(...) or the predictions API with result=["label-a", ...] or result=[['x'], {...}] — i.e. a list whose items are not dicts — instead of the required [{...}, {...}] format.

Common situations: ML backend returning a flat list of labels that is passed through unchanged; hand-written scripts building predictions from raw model output; confusing the compact single-value format (string) with the full list format; JSON where items were serialized as arrays instead of objects.

Related errors


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