HumanSignal/label-studio · error · ValueError

Failed to read file

Error message

Failed to read file {path}: {str(e)}

What it means

When Local Files import storage reads a task file that is not in use_blob_urls mode, it opens the file and parses it with load_tasks_json. If the open/read raises OSError (permission denied, file deleted between scan and read, I/O error), get_data wraps it in a ValueError carrying the OS message. This surfaces during storage sync when converting scanned files into tasks.

Solutions

  1. Fix file permissions so the Label Studio process user can read them (chmod/chown, or match UID in the container)
  2. Re-scan/re-sync so deleted files are removed from the pending list, and remove stale/broken symlinks from the directory
  3. Check the OS message embedded in the error (e.g. 'Permission denied' vs 'No such file or directory') to pick between permission and missing-file fixes
  4. If the files are raw images/blobs rather than task JSON, enable use_blob_urls so they are referenced as URLs instead of parsed

Example fix

// before
# host file: -rw------- root root task.json, Label Studio runs as appuser -> OSError
// after
sudo chown -R 10001:10001 /label-studio/data/dataset1   # or chmod o+r the task files
Defensive patterns

Strategy: try-catch

Validate before calling

import os
path = '/label-studio/data/dataset1/task.json'
if not os.path.isfile(path) or not os.access(path, os.R_OK):
    raise SystemExit(f'File missing or unreadable by Label Studio user: {path}')

Type guard

def is_readable_file(path: str) -> bool:
    from pathlib import Path
    p = Path(path)
    return p.is_file() and os.access(p, os.R_OK)

Try / catch

try:
    tasks = storage.get_data(key)
except ValueError as e:
    logger.error('Local file read failed during sync: %s — check permissions/staleness', e)

Prevention

When it happens

Trigger: Syncing a Local Files import storage where a scanned file cannot be opened: file permissions unreadable by the Label Studio process user, the file was removed after the directory scan, a broken symlink, or a disk/device error during read.

Common situations: Files owned by root while Label Studio runs as another user in Docker; NFS/bind-mount permission mismatches; race between dataset regeneration and a sync; files with restrictive modes like 0600.

Understand the failure class

Background: "failed to read file", EACCES, ENOENT and "could not read <path>" errors: when a program can't read a file from disk — this error's family across 49 libraries.

Related errors


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

Appendix: source

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

    def get_data(self, key) -> list[StorageObject]:
        path = Path(key)
        if self.use_blob_urls:
            # include self-hosted links pointed to local resources via
            # {settings.HOSTNAME}/data/local-files?d=<path/to/local/dir>
            document_root = Path(settings.LOCAL_FILES_DOCUMENT_ROOT)
            relative_path = str(path.relative_to(document_root))
            task = {
                settings.DATA_UNDEFINED_NAME: f'{settings.HOSTNAME}/data/local-files/?d={quote(str(relative_path))}'
            }
            return [StorageObject(key=key, task_data=task)]

        try:
            with open(path, 'rb') as f:
                blob = f.read()
                return load_tasks_json(blob, key)
        except OSError as e:
            raise ValueError(f'Failed to read file {path}: {str(e)}')

    def scan_and_create_links(self):
        return self._scan_and_create_links(LocalFilesImportStorageLink)

    class Meta:
        abstract = True


class LocalFilesImportStorage(ProjectStorageMixin, LocalFilesImportStorageBase):
    class Meta:
        abstract = False


class LocalFilesExportStorage(LocalFilesMixin, ExportStorage):
    def save_annotation(self, annotation):
        logger.debug(f'Creating new object on {self.__class__.__name__} Storage {self} for annotation {annotation}')
        ser_annotation = self._get_serialized_data(annotation)

View on GitHub (pinned to 0b49e9b539)