HumanSignal/label-studio · error · DRFValidationError

_stringify_detail(detail)

Error message

_stringify_detail(detail)

What it means

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).

Source

Thrown at label_studio/io_storages/localfiles/serializers.py:42

class LocalFilesImportStorageSerializer(ImportStorageSerializer):
    type = StorageTypeField(default=os.path.basename(os.path.dirname(__file__)))

    class Meta:
        model = LocalFilesImportStorage
        fields = '__all__'

    def validate(self, data):
        # Validate local file path
        data = super(LocalFilesImportStorageSerializer, self).validate(data)
        if 'path' in data:
            data['path'] = normalize_storage_path(data['path'])
        storage = LocalFilesImportStorage(**data)
        try:
            storage.validate_connection()
        except (DjangoValidationError, DRFValidationError) as exc:
            detail = getattr(exc, 'detail', getattr(exc, 'messages', str(exc)))
            raise DRFValidationError(_stringify_detail(detail))
        except Exception as exc:
            raise DRFValidationError(extract_message(exc))
        return data


class LocalFilesExportStorageSerializer(ExportStorageSerializer):
    type = StorageTypeField(default=os.path.basename(os.path.dirname(__file__)))

    class Meta:
        model = LocalFilesExportStorage
        fields = '__all__'

    def validate(self, data):
        # Validate local file path
        data = super(LocalFilesExportStorageSerializer, self).validate(data)
        if 'path' in data:
            data['path'] = normalize_storage_path(data['path'])
        storage = LocalFilesExportStorage(**data)

View on GitHub (pinned to 0b49e9b539)

Solutions

  1. 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)
  2. Inspect the response body's detail field — it mirrors the underlying ValidationError messages verbatim
  3. Pre-validate the path client-side (exists, under document root) before calling the API

Example fix

// before
POST /api/storages/localfiles/ {"path": "/does/not/exist"}  -> 400 ["Absolute local path ... does not exist"]
// after
mkdir -p /label-studio/data/dataset1
POST /api/storages/localfiles/ {"path": "/label-studio/data/dataset1"}  -> 201
Defensive patterns

Strategy: try-catch

Validate before calling

from pathlib import Path
def path_is_valid(path, doc_root):
    p, r = Path(path), Path(doc_root)
    return p.exists() and r in p.parents

Try / catch

try:
    resp = requests.post(f'{host}/api/storages/localfiles/', json=payload)
    resp.raise_for_status()
except requests.HTTPError:
    for msg in resp.json().get('detail', []):
        print('Local storage validation failed:', msg)

Prevention

When it happens

Trigger: 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).

Common situations: 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.

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/03d91c6bac643500. Report an issue: GitHub.