{"record":{"id":"b627d2851195a4d7","repo":"unslothai/unsloth","slug":"linked-folder-no-longer-resolves-to-its-registered","errorCode":null,"errorMessage":"Linked folder no longer resolves to its registered path","messagePattern":"Linked folder no longer resolves to its registered path","errorType":"exception","errorClass":"RuntimeError","httpStatus":null,"severity":"error","filePath":"studio/backend/core/rag/folder_sync.py","lineNumber":173,"sourceCode":"            raise ValueError(\"The entire home folder cannot be registered\")\n    except RuntimeError:\n        pass\n    if contains_sensitive_path_component(normalized):\n        raise ValueError(\"Credential or configuration directories are not allowed\")\n    if is_denied_system_path(normalized):\n        raise ValueError(\"System directories are not allowed\")\n    return normalized\n\n\ndef _root_identity(root: str) -> tuple[int, int]:\n    try:\n        root_stat = os.lstat(root)\n    except OSError as exc:\n        raise RuntimeError(\"Linked folder is unavailable\") from exc\n    if stat.S_ISLNK(root_stat.st_mode) or not stat.S_ISDIR(root_stat.st_mode):\n        raise RuntimeError(\"Linked folder is no longer a regular directory\")\n    if os.path.normcase(os.path.realpath(root)) != os.path.normcase(root):\n        raise RuntimeError(\"Linked folder no longer resolves to its registered path\")\n    return root_stat.st_dev, root_stat.st_ino\n\n\ndef _store_identity(identity: tuple[int, int]) -> tuple[int | str, int | str]:\n    return tuple(value if value <= _SQLITE_INTEGER_MAX else f\"x{value:x}\" for value in identity)\n\n\ndef _file_identity(metadata: dict) -> tuple[int | str, int | str]:\n    return _store_identity((metadata[\"device\"], metadata[\"inode\"]))\n\n\ndef _load_identity(device_id: int | str, file_id: int | str) -> tuple[int, int]:\n    def load(value: int | str) -> int:\n        return (\n            int(value[1:], 16) if isinstance(value, str) and value.startswith(\"x\") else int(value)\n        )\n\n    return load(device_id), load(file_id)","sourceCodeStart":155,"sourceCodeEnd":191,"githubUrl":"https://github.com/unslothai/unsloth/blob/203007d19051dcd2ae33876786d117c99f6b0368/studio/backend/core/rag/folder_sync.py#L155-L191","documentation":"Thrown by _root_identity() when the registered linked folder path resolves through a symlink or other indirection at scan/sync time: realpath(root) no longer equals the normalized stored path. The module enforces that a linked folder root stays a real directory that resolves exactly to the path registered in the linked_folders table, so a root swapped to a symlink (or mounted over) is treated as a security/integrity failure rather than silently synced.","triggerScenarios":"Any sync job, scan (_scan), or create_folder/_reauthorize_folder call that invokes _root_identity on a stored path where realpath() differs: an administrator replaced the directory with a symlink, a bind-mount/symlink farm was introduced after registration, or the folder was registered before symlink rules existed and realpath now canonicalizes differently (e.g. /tmp -> /private/tmp on macOS).","commonSituations":"macOS /tmp vs /private/tmp case sensitivity mismatch, Docker volumes mounted as symlinks, users 'reorganizing' data by symlinking the old directory name, network shares whose realpath changes after remount.","solutions":["Replace the symlink with a real directory (or move the data back so the registered path is a real directory), then re-run sync.","If the data moved, remove the linked folder and register the new concrete path via create_folder.","Re-register the folder using its fully resolved real path (realpath output) so realpath(root) == root holds.","Check os.path.realpath and os.path.islink on the stored path before each sync and surface a re-authorization prompt to the user."],"exampleFix":"# before\nln -s /mnt/newdata /home/user/linked_data  # registered path now a symlink\n\n# after\nrm /home/user/linked_data && mv /mnt/newdata /home/user/linked_data  # real directory again","handlingStrategy":"validation","validationCode":"import os, stat\n\ndef root_resolves_to_registered(path: str) -> bool:\n    st = os.lstat(path)\n    return not stat.S_ISLNK(st.st_mode) and stat.S_ISDIR(st.st_mode) and \\\n        os.path.normcase(os.path.realpath(path)) == os.path.normcase(path)","typeGuard":null,"tryCatchPattern":"try:\n    sync_folder(...)\nexcept RuntimeError as e:\n    if \"no longer resolves\" in str(e):\n        mark_folder_needs_relink(folder_id)  # prompt user to re-register\n    else:\n        raise","preventionTips":["Register linked folders by their realpath output, never a symlinked alias.","Avoid registering paths under macOS /tmp (realpath maps to /private/tmp).","Never replace a linked directory with a symlink during reorganization; move the data back or re-register the new path."],"tags":["filesystem","symlink","rag","folder-sync","integrity"],"backgroundTag":null,"analyzedSha":"203007d19051dcd2ae33876786d117c99f6b0368","analyzedAt":"2026-08-15T02:48:39.846Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}