unslothai/unsloth · error · NativePathLeaseError

Native path grant has an unsupported file type.

Error message

Native path grant has an unsupported file type.

What it means

The caller passed allowed_suffixes and the resolved path's extension (lowercased) is not in that set. This is an extension-level file-type gate applied after signature verification — e.g. a GGUF import endpoint passes allowed_suffixes=('.gguf',) so a signed-but-wrong file type is rejected before any read.

Source

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

        operation = str(payload["operation"]),
        canonical_path = resolved,
        path_kind = str(payload["path_kind"]),
        path_type = str(payload["path_type"]),
        source_kind = str(payload["source_kind"]),
        token_id_hash = str(payload["token_id_hash"]),
        display_label = str(payload.get("display_label") or resolved.name),
        expires_at_ms = _required_int(payload, "expires_at_ms"),
        size_bytes = _optional_int(payload.get("size_bytes")),
        modified_ms = _optional_int(payload.get("modified_ms")),
        device_id = identity_options[0][0] if identity_options else None,
        file_id = identity_options[0][1] if identity_options else None,
    )

    if expected_path_type and grant.path_type != expected_path_type:
        raise NativePathLeaseError("Native path grant has the wrong path type.")
    suffixes = tuple(s.lower() for s in (allowed_suffixes or ()))
    if suffixes and resolved.suffix.lower() not in suffixes:
        raise NativePathLeaseError("Native path grant has an unsupported file type.")

    current_identity = _validate_current_stat(grant, identity_options)
    if current_identity is not None:
        grant = replace(grant, device_id = current_identity[0], file_id = current_identity[1])
    _consume_nonce(str(payload["nonce"]), grant.expires_at_ms)
    _remember_native_path_for_redaction(str(resolved), grant.display_label)
    return grant


def display_label_for_native_path(value: str | None) -> str | None:
    if not value:
        return value
    with _REDACTION_LOCK:
        return _NATIVE_PATH_LABELS.get(value, value)


def is_registered_native_path_label(path_value: str | None, label: str | None) -> bool:
    if not path_value or not label:

View on GitHub (pinned to 203007d190)

Solutions

  1. Have the user re-select a file whose extension matches what the endpoint accepts (e.g. .gguf).
  2. Sync the native dialog's file filter with the backend's allowed_suffixes for that endpoint so mismatches can't be picked in the first place.
  3. If a legitimate new format should be accepted, add its suffix to allowed_suffixes in the backend call site.
  4. Check for trailing whitespace or compound extensions on the filename (only the final .suffix segment is compared).

Example fix

# before
verify_native_path_lease(lease, operation="import_gguf", allowed_suffixes=(".gguf",))
# user selected weights.safetensors -> error

# after (frontend restricts the dialog)
const lease = await pickNativeFile({ filters: [{ name: "GGUF", extensions: ["gguf"] }] });
verify_native_path_lease(lease, operation="import_gguf", allowed_suffixes=(".gguf",))
Defensive patterns

Strategy: validation

Validate before calling

from pathlib import Path

ALLOWED = {".gguf"}

def suffix_ok(path_str: str) -> bool:
    return Path(path_str).suffix.lower() in ALLOWED

Try / catch

try:
    grant = verify_native_path_lease(lease, operation=OP, allowed_suffixes=(".gguf",))
except NativePathLeaseError as exc:
    if "unsupported file type" in str(exc):
        return error_response(400, "Only .gguf files are supported here.")
    raise

Prevention

When it happens

Trigger: User picks a file with a different extension than the endpoint allows (e.g. .safetensors for a .gguf-only import); the file has no extension at all; double extensions where only the last suffix counts; or frontend filters on the dialog not matching the backend's allowed_suffixes list.

Common situations: Dialog file filters drifted out of sync with backend allowed_suffixes after a code change; users renaming files to force them through; case differences are handled (comparison is lowercased) but compound suffixes like .gguf.part or archive.gguf.tmp are not in the list.

Related errors


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