unslothai/unsloth · error · NativePathLeaseError

Native path grant has an unsupported path type.

Error message

Native path grant has an unsupported path type.

What it means

The signed payload's path_type is neither "file" nor "directory", so the backend does not know how to validate the on-disk object. This is a signer/backend contract violation: verify_native_path_lease() only understands grants for files and directories. It indicates the Rust signer emitted an unknown path_type value or the backend is older than the signer.

Source

Thrown at studio/backend/utils/native_path_leases.py:359


def _validate_current_stat(
    grant: NativePathGrant, identity_options: tuple[tuple[int, int], ...]
) -> tuple[int, int] | None:
    try:
        st = os.lstat(grant.canonical_path)
    except OSError as exc:
        raise NativePathLeaseError("Native path is no longer accessible.") from exc
    if _stat_module.S_ISLNK(st.st_mode):
        raise NativePathLeaseError("Native path is no longer a regular file.")
    if grant.path_type == "file":
        if not _stat_module.S_ISREG(st.st_mode):
            raise NativePathLeaseError("Native path is no longer a regular file.")
    elif grant.path_type == "directory":
        if not _stat_module.S_ISDIR(st.st_mode):
            raise NativePathLeaseError("Native path is no longer a directory.")
    else:
        raise NativePathLeaseError("Native path grant has an unsupported path type.")

    if grant.size_bytes is not None and st.st_size != grant.size_bytes:
        raise NativePathLeaseError("Native path changed after it was selected.")
    current_modified_ms = int(st.st_mtime_ns // 1_000_000)
    if grant.modified_ms is not None and current_modified_ms != grant.modified_ms:
        raise NativePathLeaseError("Native path changed after it was selected.")
    if grant.path_kind == "document-folder" and not identity_options:
        raise NativePathLeaseError("Native path grant is missing its folder identity.")
    current_identity = (st.st_dev, st.st_ino)
    expected_identity = _runtime_identity(identity_options)
    if expected_identity is not None and current_identity != expected_identity:
        raise NativePathLeaseError("Native path changed after it was selected.")
    return current_identity if expected_identity is not None else None


def _consume_nonce(nonce: str, expires_at_ms: int) -> None:
    now_ms = int(time.time() * 1000)
    with _REPLAY_LOCK:

View on GitHub (pinned to 203007d190)

Solutions

  1. Decode the grant payload and read its path_type value to see what the signer emitted.
  2. Update the Python backend (studio) and the Tauri desktop shell together so both agree on the path_type vocabulary.
  3. If you maintain the signer, restrict path_type to 'file' or 'directory' until the backend supports more kinds.
  4. Re-select the path after updating to obtain a grant with a supported type.

Example fix

// before (Rust signer)
"path_type": if is_symlink { "symlink" } else { "file" }, // unsupported value

// after
"path_type": "file", // only 'file' | 'directory' are valid
Defensive patterns

Strategy: type-guard

Validate before calling

import base64, json

SUPPORTED_PATH_TYPES = {'file', 'directory'}

def grant_path_type_supported(lease: str) -> bool:
    payload = json.loads(base64.urlsafe_b64decode(lease.split('.')[0] + '=='))
    return payload.get('path_type') in SUPPORTED_PATH_TYPES

Type guard

SUPPORTED_PATH_TYPES = {'file', 'directory'}

def is_supported_path_type(value: object) -> bool:
    return isinstance(value, str) and value in SUPPORTED_PATH_TYPES

Try / catch

try:
    grant = verify_native_path_lease(lease, operation='read')
except NativePathLeaseError as exc:
    if 'unsupported path type' in str(exc):
        return respond(400, 'Desktop app and backend versions differ; update both and re-select.')
    raise

Prevention

When it happens

Trigger: verify_native_path_lease() with payload['path_type'] not in {'file','directory'}: a new signer version introduced 'symlink' or 'drive' types; a test payload hand-built with a wrong string; version mismatch after a partial desktop-app update.

Common situations: Desktop app updated the Rust shell but not the Python backend (or vice versa); custom forks adding new path kinds without updating this validator; fuzz/corpus testing with arbitrary path_type strings.

Related errors


AI-assisted analysis of unslothai/unsloth@203007d190 (2026-08-15). Data as JSON: /api/errors/504737b4b2c8a206. Report an issue: GitHub.