{"record":{"id":"389e929fee29cf4c","repo":"HumanSignal/label-studio","slug":"value-must-be-a-list","errorCode":null,"errorMessage":"Value must be a list","messagePattern":"Value must be a list","errorType":"validation","errorClass":"ValidationError","httpStatus":400,"severity":"error","filePath":"label_studio/ml_models/models.py","lineNumber":27,"sourceCode":"from ml_model_providers.models import ModelProviderConnection, ModelProviders\nfrom projects.models import Project\nfrom rest_framework.exceptions import ValidationError\nfrom tasks.models import Annotation, FailedPrediction, Prediction, PredictionMeta\n\nlogger = logging.getLogger(__name__)\n\n\n# skills are partitions of projects (label config + input columns + output columns) into categories of labeling tasks\nclass SkillNames(models.TextChoices):\n    TEXT_CLASSIFICATION = 'TextClassification', _('TextClassification')\n    NAMED_ENTITY_RECOGNITION = 'NamedEntityRecognition', _('NamedEntityRecognition')\n\n\ndef validate_string_list(value):\n    if not value:\n        raise ValidationError('list should not be empty')\n    if not isinstance(value, list):\n        raise ValidationError('Value must be a list')\n    if not all(isinstance(item, str) for item in value):\n        raise ValidationError('All items in the list must be strings')\n\n\nclass ModelInterface(models.Model):\n    title = models.CharField(_('title'), max_length=500, null=False, blank=False, help_text='Model name')\n\n    description = models.TextField(_('description'), null=True, blank=True, help_text='Model description')\n\n    created_by = models.ForeignKey(\n        settings.AUTH_USER_MODEL, related_name='created_models', on_delete=models.SET_NULL, null=True\n    )\n\n    created_at = models.DateTimeField(_('created at'), auto_now_add=True)\n\n    updated_at = models.DateTimeField(_('updated at'), auto_now=True)\n\n    organization = models.ForeignKey(","sourceCodeStart":9,"sourceCodeEnd":45,"githubUrl":"https://github.com/HumanSignal/label-studio/blob/0b49e9b53917880baf1dd85d574fe5541a9aafb2/label_studio/ml_models/models.py#L9-L45","documentation":"DRF ValidationError from validate_string_list raised when the value is not a Python list (e.g. a comma-separated string, dict, or scalar). The validator checks type after the emptiness check.","triggerScenarios":"Submitting a ModelInterface field as a string like \"a,b\" or a JSON object instead of a JSON array when creating/updating an ML model interface.","commonSituations":"Sending comma-separated strings from clients; JSON schema mismatch between ML backend and Label Studio; YAML/JSON config parsing producing a dict instead of a list.","solutions":["Send the value as a JSON array, e.g. [\"a\",\"b\"] instead of \"a,b\"","Split strings client-side before submission","Align the ML backend's returned interface format with the expected list schema"],"exampleFix":"// before\n{\"labels\": \"class_a,class_b\"}\n// after\n{\"labels\": [\"class_a\", \"class_b\"]}","handlingStrategy":"type-guard","validationCode":"if not isinstance(value, list):\n    if isinstance(value, str):\n        value = value.split(',')  # coerce common string form","typeGuard":"def is_str_list(v) -> bool:\n    return isinstance(v, list)","tryCatchPattern":"try:\n    interface.full_clean()\nexcept ValidationError as e:\n    if 'Value must be a list' in str(e):\n        value = [s.strip() for s in str(value).split(',')]","preventionTips":["Always serialize list fields as JSON arrays, not comma strings","Fix JSON/YAML config parsing so lists stay lists","Add client-side schema validation matching the validator rules"],"tags":["validation","ml","type-error","drf"],"backgroundTag":"type-validation-failed","analyzedSha":"0b49e9b53917880baf1dd85d574fe5541a9aafb2","analyzedAt":"2026-08-29T00:39:52.578Z","schemaVersion":2},"datasetVersion":"2026-08-29T02:17:18.158Z"}