HumanSignal/label-studio · error · ValidationError

Absolute local path "{self.path}" must be a subdirectory of

Error message

Absolute local path "{self.path}" must be a subdirectory of LOCAL_FILES_DOCUMENT_ROOT="{settings.LOCAL_FILES_DOCUMENT_ROOT}" by security reasons. For example: "{example_path}".

What it means

Local Files storage paths must live inside LOCAL_FILES_DOCUMENT_ROOT; validate_connection checks document_root not in path.parents and raises this Django ValidationError otherwise. This confinement prevents path-traversal-style access to arbitrary host filesystem locations. It fires when the given absolute path is outside, above, or unrelated to the configured document root.

Source

Thrown at label_studio/io_storages/localfiles/models.py:94

        return ''

    def validate_connection(self):
        normalized_path = self._get_storage_path_or_raise(ValidationError)
        self.path = normalized_path
        path = Path(normalized_path)
        document_root = Path(settings.LOCAL_FILES_DOCUMENT_ROOT)
        example_path = Path(settings.LOCAL_FILES_DOCUMENT_ROOT) / 'dataset1'

        if not path.exists():
            raise ValidationError(f'Absolute local path "{self.path}" does not exist')
        if document_root == path:
            raise ValidationError(
                f'Absolute local path "{self.path}" cannot be the same as '
                f'LOCAL_FILES_DOCUMENT_ROOT="{settings.LOCAL_FILES_DOCUMENT_ROOT}" by security reasons. Please add a subdirectory. '
                f'For example: "{example_path}".'
            )
        if document_root not in path.parents:
            raise ValidationError(
                f'Absolute local path "{self.path}" must be a subdirectory of '
                f'LOCAL_FILES_DOCUMENT_ROOT="{settings.LOCAL_FILES_DOCUMENT_ROOT}" by security reasons. '
                f'For example: "{example_path}".'
            )
        if settings.LOCAL_FILES_SERVING_ENABLED is False:
            raise ValidationError(
                'Serving local files from the host filesystem can be a security risk, so '
                'LOCAL_FILES_SERVING_ENABLED is disabled by default. '
                'To enable Local Files storage, set the LOCAL_FILES_SERVING_ENABLED environment '
                'variable to "true" and restart Label Studio. See '
                'https://labelstud.io/guide/storage.html#Local-storage for details.'
                '\n\n'
                f'{self.community_auto_hint()}'
            )


class LocalFilesImportStorageBase(LocalFilesMixin, ImportStorage):
    url_scheme = 'https'

View on GitHub (pinned to 0b49e9b539)

Solutions

  1. Either move/symlink the data under LOCAL_FILES_DOCUMENT_ROOT and use that path, or set LOCAL_FILES_DOCUMENT_ROOT to a common ancestor of the storage path and restart Label Studio
  2. For Docker, mount the data at a path inside the document root (-v /your/data:/label-studio/data/local-files/<name>)
  3. Avoid relative or ..-containing paths; always pass a normalized absolute subdirectory of the document root

Example fix

// before
LOCAL_FILES_DOCUMENT_ROOT=/label-studio/data
{ "path": "/home/user/datasets/tweets" }   // outside document root
// after
LOCAL_FILES_DOCUMENT_ROOT=/label-studio/data
# mount: -v /home/user/datasets:/label-studio/data/local-files/datasets
{ "path": "/label-studio/data/local-files/datasets/tweets" }
Defensive patterns

Strategy: validation

Validate before calling

from pathlib import Path
p, root = Path(path), Path('/label-studio/data')
if not (p.is_absolute() and root in p.parents):
    raise SystemExit(f'Path must be a subdirectory of {root}')

Try / catch

try:
    storage.validate_connection()
except ValidationError as e:
    if 'must be a subdirectory of' in ';'.join(e.messages):
        logger.error('Move data under %s or adjust LOCAL_FILES_DOCUMENT_ROOT', e)
    else:
        raise

Prevention

When it happens

Trigger: Creating/updating a Local Files storage with a path like /home/user/data or /tmp/data while LOCAL_FILES_DOCUMENT_ROOT is /label-studio/data; using '..' or symlink tricks that resolve outside the root; changing LOCAL_FILES_DOCUMENT_ROOT after the storage was created without updating the path.

Common situations: Docker containers where the data volume was mounted at a different location than the path entered; local dev on macOS/Windows paths that don't match the server's document root; users unaware that LOCAL_FILES_DOCUMENT_ROOT must be set to cover their data directory.

Related errors


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