You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Auto-configure Local Files root in Community Edition when env vars are missing – Added backend autodetection of LOCAL_FILES_DOCUMENT_ROOT and LOCAL_FILES_SERVING_ENABLED via autodetect_local_files_root(), scanning for mydata / label-studio-data under the current working directory and logging the chosen root when found.
Documented Community Edition Docker auto-detection for Local Storage – Updated the storage guide to explain that, in Community Edition, Label Studio automatically uses mydata or label-studio-data in the working directory as the local files root when related environment variables are unset, including Docker mount examples.
Hardened Local Files storage path handling and validation – Introduced normalize_storage_path() and a migration to canonicalize stored paths (trim, normalize separators, remove trailing slashes), enforced normalization on save/clean, and tightened validation so paths must exist, cannot equal LOCAL_FILES_DOCUMENT_ROOT, and must be strict subdirectories with clearer error messages and Community Edition hints. See "Problem with path normalization" section below for details.
Refactored Local Files download endpoint into the storage app with ETag support
Moved /data/local-files/ handling from core views into io_storages.localfiles, preserved permission checks over LocalFilesImportStorage, and
Added weak ETag generation plus If-None-Match handling to return 304 Not Modified when appropriate.
Aligned Local Files export lifecycle with annotation deletion – Extended LocalFilesExportStorage with a deletion API and a pre_delete signal hook so that exported files and links are removed when annotations are deleted, while respecting can_delete_objects to keep disk artifacts when deletion is disabled.
Improved Local Files serializers and surfaced field-level validation errors – Updated serializers to normalize paths, catch both Django and DRF validation errors, stringify nested error structures, and consistently re-raise them as DRF ValidationError, enabling the UI to display precise backend validation messages per field.
Enhanced Storage Settings UI for Local Files configuration – Reworked the Local Files provider into a React-based config with a dedicated warning when local file serving is disabled, Community Edition tips for automatic enablement (including Docker mount hints), and doc-root–aware default path suggestions plus new Storage Settings styling.
Made StorageProviderForm respect backend validation and custom defaults – Added defaultValue support on provider fields, improved default extraction logic, wired the storage API hook to intercept 400 responses with validation_errors, and merged those into the form’s error state so server-side validation shows inline on the corresponding inputs.
Extended shared UI components and reduced log noise – Introduced an info variant for the Alert component, added a TypeScript declaration file for the InlineError component, and suppressed verbose Faker and Redis “not connected” warnings to keep logs cleaner.
Backed changes with focused test coverage – Added tests for Local Files path normalization, validation rules, serializer behavior, ETag/304 download handling, and export-file cleanup, plus pytest fixtures to let IO storage tests run in isolation.
Problem with path normalization
Local Files access was brittle because LocalFilesImportStorage.path stored whatever users typed (with or without trailing slashes and with mixed / and \ separators). The /data/local-files/?d=… view checked permissions by comparing the requested file’s directory against storage.path prefixes in the database; when paths didn’t match exactly (for example /home/user/dataset vs /home/user/dataset/), the prefix check failed and users saw 404s even though the storage and files were valid. A previous attempt to work around this by scanning all LocalFilesImportStorage rows in Python fixed some edge cases but made the permission check O(number_of_storages) per request and therefore not acceptable at scale.
We made Local Files storage paths canonical at the model boundary and backfilled existing rows so that all paths use a single, normalized representation. A new helper normalize_storage_path in LocalFilesMixin trims whitespace, converts backslashes to the OS separator, and runs os.path.normpath to remove redundant/trailing separators; this helper is applied in clean(), save(), and in the serializers before validation, so both new and updated LocalFilesImportStorage/LocalFilesExportStorage rows are stored consistently. A data migration (0022_normalize_localfiles_paths) uses the same helper to normalize all existing rows in-place, which is a simple bounded update (no async job needed) and keeps runtime behavior uniform across deployments.
With all storage paths canonical, the /data/local-files view goes back to using an efficient database-side filter instead of a Python scan: it normalizes the requested file’s directory once and uses an annotated _full_path__startswith=F('path') query to select only candidate storages, then checks project permissions as before. We added focused tests for normalize_storage_path (including trailing slashes, mixed separators, and Windows-style inputs) plus an end‑to‑end view test to prove that storages configured with trailing slashes or backslashes still resolve correctly. Overall, the fix removes the user-facing 404s caused by path formatting, keeps behavior consistent across OSes, and restores the original scalable query pattern for large numbers of Local Files storages.
UI Improvements
New icon:
Improved error display:
Alerts for env variables:
Absolute local path is automatically preloaded from LOCAL_FILES_DOCUMENT_ROOT:
❌ Patch coverage is 94.72296% with 20 lines in your changes missing coverage. Please review.
✅ Project coverage is 65.11%. Comparing base (7502391) to head (581b91a). ⚠️ Report is 1 commits behind head on develop.
✅ All tests successful. No failed tests found.
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Improvements and fixes
Auto-configure Local Files root in Community Edition when env vars are missing – Added backend autodetection of
LOCAL_FILES_DOCUMENT_ROOTandLOCAL_FILES_SERVING_ENABLEDviaautodetect_local_files_root(), scanning formydata/label-studio-dataunder the current working directory and logging the chosen root when found.Documented Community Edition Docker auto-detection for Local Storage – Updated the storage guide to explain that, in Community Edition, Label Studio automatically uses
mydataorlabel-studio-datain the working directory as the local files root when related environment variables are unset, including Docker mount examples.Hardened Local Files storage path handling and validation – Introduced
normalize_storage_path()and a migration to canonicalize stored paths (trim, normalize separators, remove trailing slashes), enforced normalization on save/clean, and tightened validation so paths must exist, cannot equalLOCAL_FILES_DOCUMENT_ROOT, and must be strict subdirectories with clearer error messages and Community Edition hints. See "Problem with path normalization" section below for details.Refactored Local Files download endpoint into the storage app with ETag support
/data/local-files/handling from core views intoio_storages.localfiles, preserved permission checks overLocalFilesImportStorage, andIf-None-Matchhandling to return304 Not Modifiedwhen appropriate.Aligned Local Files export lifecycle with annotation deletion – Extended
LocalFilesExportStoragewith a deletion API and apre_deletesignal hook so that exported files and links are removed when annotations are deleted, while respectingcan_delete_objectsto keep disk artifacts when deletion is disabled.Improved Local Files serializers and surfaced field-level validation errors – Updated serializers to normalize paths, catch both Django and DRF validation errors, stringify nested error structures, and consistently re-raise them as DRF
ValidationError, enabling the UI to display precise backend validation messages per field.Enhanced Storage Settings UI for Local Files configuration – Reworked the Local Files provider into a React-based config with a dedicated warning when local file serving is disabled, Community Edition tips for automatic enablement (including Docker mount hints), and doc-root–aware default path suggestions plus new Storage Settings styling.
Made StorageProviderForm respect backend validation and custom defaults – Added
defaultValuesupport on provider fields, improved default extraction logic, wired the storage API hook to intercept400responses withvalidation_errors, and merged those into the form’s error state so server-side validation shows inline on the corresponding inputs.Extended shared UI components and reduced log noise – Introduced an
infovariant for theAlertcomponent, added a TypeScript declaration file for theInlineErrorcomponent, and suppressed verbose Faker and Redis “not connected” warnings to keep logs cleaner.Backed changes with focused test coverage – Added tests for Local Files path normalization, validation rules, serializer behavior, ETag/304 download handling, and export-file cleanup, plus pytest fixtures to let IO storage tests run in isolation.
Problem with path normalization
Local Files access was brittle because LocalFilesImportStorage.path stored whatever users typed (with or without trailing slashes and with mixed / and \ separators). The /data/local-files/?d=… view checked permissions by comparing the requested file’s directory against storage.path prefixes in the database; when paths didn’t match exactly (for example /home/user/dataset vs /home/user/dataset/), the prefix check failed and users saw 404s even though the storage and files were valid. A previous attempt to work around this by scanning all LocalFilesImportStorage rows in Python fixed some edge cases but made the permission check O(number_of_storages) per request and therefore not acceptable at scale.
We made Local Files storage paths canonical at the model boundary and backfilled existing rows so that all paths use a single, normalized representation. A new helper normalize_storage_path in LocalFilesMixin trims whitespace, converts backslashes to the OS separator, and runs os.path.normpath to remove redundant/trailing separators; this helper is applied in clean(), save(), and in the serializers before validation, so both new and updated LocalFilesImportStorage/LocalFilesExportStorage rows are stored consistently. A data migration (0022_normalize_localfiles_paths) uses the same helper to normalize all existing rows in-place, which is a simple bounded update (no async job needed) and keeps runtime behavior uniform across deployments.
With all storage paths canonical, the /data/local-files view goes back to using an efficient database-side filter instead of a Python scan: it normalizes the requested file’s directory once and uses an annotated _full_path__startswith=F('path') query to select only candidate storages, then checks project permissions as before. We added focused tests for normalize_storage_path (including trailing slashes, mixed separators, and Windows-style inputs) plus an end‑to‑end view test to prove that storages configured with trailing slashes or backslashes still resolve correctly. Overall, the fix removes the user-facing 404s caused by path formatting, keeps behavior consistent across OSes, and restores the original scalable query pattern for large numbers of Local Files storages.
UI Improvements
New icon:

Improved error display:

Alerts for env variables:

Absolute local path is automatically preloaded from LOCAL_FILES_DOCUMENT_ROOT:
