{"record":{"id":"03d91c6bac643500","repo":"HumanSignal/label-studio","slug":"stringify-detail-detail","errorCode":null,"errorMessage":"_stringify_detail(detail)","messagePattern":"_stringify_detail\\(detail\\)","errorType":"validation","errorClass":"DRFValidationError","httpStatus":400,"severity":"error","filePath":"label_studio/io_storages/localfiles/serializers.py","lineNumber":42,"sourceCode":"\nclass LocalFilesImportStorageSerializer(ImportStorageSerializer):\n    type = StorageTypeField(default=os.path.basename(os.path.dirname(__file__)))\n\n    class Meta:\n        model = LocalFilesImportStorage\n        fields = '__all__'\n\n    def validate(self, data):\n        # Validate local file path\n        data = super(LocalFilesImportStorageSerializer, self).validate(data)\n        if 'path' in data:\n            data['path'] = normalize_storage_path(data['path'])\n        storage = LocalFilesImportStorage(**data)\n        try:\n            storage.validate_connection()\n        except (DjangoValidationError, DRFValidationError) as exc:\n            detail = getattr(exc, 'detail', getattr(exc, 'messages', str(exc)))\n            raise DRFValidationError(_stringify_detail(detail))\n        except Exception as exc:\n            raise DRFValidationError(extract_message(exc))\n        return data\n\n\nclass LocalFilesExportStorageSerializer(ExportStorageSerializer):\n    type = StorageTypeField(default=os.path.basename(os.path.dirname(__file__)))\n\n    class Meta:\n        model = LocalFilesExportStorage\n        fields = '__all__'\n\n    def validate(self, data):\n        # Validate local file path\n        data = super(LocalFilesExportStorageSerializer, self).validate(data)\n        if 'path' in data:\n            data['path'] = normalize_storage_path(data['path'])\n        storage = LocalFilesExportStorage(**data)","sourceCodeStart":24,"sourceCodeEnd":60,"githubUrl":"https://github.com/HumanSignal/label-studio/blob/0b49e9b53917880baf1dd85d574fe5541a9aafb2/label_studio/io_storages/localfiles/serializers.py#L24-L60","documentation":"The Local Files import storage serializer intercepts Django/DRF ValidationErrors from storage.validate_connection and re-raises them as DRF ValidationError after flattening exc.detail (or exc.messages) with _stringify_detail. The raised value is the stringified detail, so a Django ValidationError like 'path does not exist' becomes an API 400 response with a JSON-serializable message. You see this form whenever the underlying cause was a Django/DRF validation failure (indices 151-154).","triggerScenarios":"POST/PATCH /api/storages/localfiles/ with a path that fails validate_connection (doesn't exist, equals document root, outside document root, or serving disabled) — the serializer converts the Django ValidationError to a DRF 400 using _stringify_detail(detail).","commonSituations":"API clients receiving 400 with a list/string message like 'Absolute local path ... does not exist'; UI storage tests showing the flattened validation text; automated scripts surprised the raw Django ValidationError is not propagated.","solutions":["Fix the root cause reported in the stringified detail (create the directory, use a subdirectory of LOCAL_FILES_DOCUMENT_ROOT, enable LOCAL_FILES_SERVING_ENABLED)","Inspect the response body's detail field — it mirrors the underlying ValidationError messages verbatim","Pre-validate the path client-side (exists, under document root) before calling the API"],"exampleFix":"// before\nPOST /api/storages/localfiles/ {\"path\": \"/does/not/exist\"}  -> 400 [\"Absolute local path ... does not exist\"]\n// after\nmkdir -p /label-studio/data/dataset1\nPOST /api/storages/localfiles/ {\"path\": \"/label-studio/data/dataset1\"}  -> 201","handlingStrategy":"try-catch","validationCode":"from pathlib import Path\ndef path_is_valid(path, doc_root):\n    p, r = Path(path), Path(doc_root)\n    return p.exists() and r in p.parents","typeGuard":null,"tryCatchPattern":"try:\n    resp = requests.post(f'{host}/api/storages/localfiles/', json=payload)\n    resp.raise_for_status()\nexcept requests.HTTPError:\n    for msg in resp.json().get('detail', []):\n        print('Local storage validation failed:', msg)","preventionTips":["Pre-validate path existence/subdirectory rules client-side","Read the stringified detail in the 400 response — it names the exact rule broken","Keep server-side settings (document root, serving flag) in sync with what the client sends"],"tags":["api","serialization","validation","django"],"backgroundTag":"schema-validation-failed","analyzedSha":"0b49e9b53917880baf1dd85d574fe5541a9aafb2","analyzedAt":"2026-08-29T00:39:52.578Z","schemaVersion":2},"datasetVersion":"2026-08-29T02:17:18.158Z"}