{"record":{"id":"2ca7ff346c64a95c","repo":"unslothai/unsloth","slug":"native-path-is-no-longer-a-regular-file","errorCode":null,"errorMessage":"Native path is no longer a regular file.","messagePattern":"Native path is no longer a regular file\\.","errorType":"validation","errorClass":"NativePathLeaseError","httpStatus":400,"severity":"error","filePath":"studio/backend/utils/native_path_leases.py","lineNumber":192,"sourceCode":"        secret,\n        payload_b64.encode(\"ascii\"),\n        hashlib.sha256,\n    ).digest()\n    supplied_signature = _b64decode(signature_b64)\n    if not hmac.compare_digest(expected_signature, supplied_signature):\n        raise NativePathLeaseError(\"Native path grant signature is invalid.\")\n\n    payload = _decode_payload(payload_b64)\n    _validate_payload(payload, operation = operation, expected_kind = expected_kind)\n\n    path = Path(str(payload[\"canonical_path\"]))\n    _reject_network_or_device_path(path)\n    try:\n        signed_lstat = os.lstat(path)\n    except OSError as exc:\n        raise NativePathLeaseError(\"Native path is no longer accessible.\") from exc\n    if _stat_module.S_ISLNK(signed_lstat.st_mode):\n        raise NativePathLeaseError(\"Native path is no longer a regular file.\")\n    try:\n        resolved = path.resolve(strict = True)\n    except OSError as exc:\n        raise NativePathLeaseError(\"Native path is no longer accessible.\") from exc\n    _reject_network_or_device_path(resolved)\n    if not _same_native_path(resolved, path):\n        raise NativePathLeaseError(\"Native path grant no longer resolves to the selected path.\")\n\n    identity_options = _identity_options(payload)\n    grant = NativePathGrant(\n        operation = str(payload[\"operation\"]),\n        canonical_path = resolved,\n        path_kind = str(payload[\"path_kind\"]),\n        path_type = str(payload[\"path_type\"]),\n        source_kind = str(payload[\"source_kind\"]),\n        token_id_hash = str(payload[\"token_id_hash\"]),\n        display_label = str(payload.get(\"display_label\") or resolved.name),\n        expires_at_ms = _required_int(payload, \"expires_at_ms\"),","sourceCodeStart":174,"sourceCodeEnd":210,"githubUrl":"https://github.com/unslothai/unsloth/blob/203007d19051dcd2ae33876786d117c99f6b0368/studio/backend/utils/native_path_leases.py#L174-L210","documentation":"lstat() shows the signed path is now a symlink. The lease scheme requires the canonical path itself to be a regular file (or directory), not a link, because symlinks can be swapped after signing to redirect the backend's read to a different target (a TOCTOU-style bypass of the path grant).","triggerScenarios":"The user (or a script) replaced the originally selected regular file with a symlink between grant issuance and verification; the path was always a symlink but was canonicalized at signing while the link was later recreated pointing elsewhere; or the selection flow signed a non-canonical path on a platform where lstat and resolve disagree.","commonSituations":"Files managed by sync tools (Dropbox/ iCloud placeholder replacement), user reorganizing with ln -s, build pipelines that swap artifact files with symlink indirection, or attempts to make a signed grant point at /etc/shadow via a symlink planted at the original location.","solutions":["Re-select the target file so the grant is issued against the current, real file.","If you control the signing side (Rust shell), ensure it signs the resolved canonical path, not a symlink path.","Reject user selections that are symlinks at pick time so a grant is never issued for one.","Do not attempt to work around this check — it is a deliberate security guard against post-signing redirection."],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":"import os, stat\n\ndef is_plain_file(path_str: str) -> bool:\n    try:\n        return not stat.S_ISLNK(os.lstat(path_str).st_mode)\n    except OSError:\n        return False","typeGuard":null,"tryCatchPattern":"try:\n    grant = verify_native_path_lease(lease, operation=OP)\nexcept NativePathLeaseError as exc:\n    if \"no longer a regular file\" in str(exc):\n        return error_response(409, \"The selected item changed on disk. Re-select it.\")\n    raise","preventionTips":["Reject symlink selections at pick time in the dialog options where possible.","Never replace selected files with symlinks in tooling while a grant is outstanding.","Treat this error as a security signal — log it, don't just retry blindly."],"tags":["symlink","security","toctou","filesystem"],"backgroundTag":null,"analyzedSha":"203007d19051dcd2ae33876786d117c99f6b0368","analyzedAt":"2026-08-15T02:48:39.846Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}