unslothai/unsloth · error · HTTPException

Native path grant is required.

Error message

Native path grant is required.

What it means

When attaching a file by native path (desktop drag-drop), the backend must first verify a signed native-path lease via verify_native_path_lease() with operation='attach', kind='attachment', path_type='file', and suffixes limited to config.UPLOAD_EXTS. Any NativePathLeaseError — including 'Native path grant is required.' when the lease token is absent, malformed, expired, or fails verification — surfaces as HTTP 400 with the lease error's text.

Source

Thrown at studio/backend/routes/rag.py:177

def _save_native_path_upload(lease: str) -> tuple[str, str]:
    """Persist a desktop drop; returns (stored_path, filename).

    The webview never gets to name a path directly: Rust signs the path it saw and we
    re-verify + re-stat that grant here before reading a byte.
    """
    from utils.native_path_leases import NativePathLeaseError, verify_native_path_lease

    try:
        grant = verify_native_path_lease(
            lease,
            operation = "attach",
            expected_kind = "attachment",
            expected_path_type = "file",
            allowed_suffixes = sorted(config.UPLOAD_EXTS),
        )
    except NativePathLeaseError as exc:
        raise HTTPException(status_code = 400, detail = str(exc)) from exc

    filename = _sanitize_filename(grant.canonical_path.name)
    try:
        with open(grant.canonical_path, "rb") as source:
            return _persist_upload_stream(
                source,
                filename,
                empty_detail = "Dropped file is empty.",
            )
    except OSError as exc:
        raise HTTPException(status_code = 400, detail = "Dropped file could not be read.") from exc


def _resolve_document_upload(
    file: UploadFile | None, native_path_lease: str | None
) -> tuple[str, str]:
    if native_path_lease:
        return _save_native_path_upload(native_path_lease)

View on GitHub (pinned to 203007d190)

Solutions

  1. Request a fresh lease from the native-path lease issuer for the exact file right before upload and pass it unchanged.
  2. Confirm the lease is for operation 'attach', kind 'attachment', path type 'file', and the file's extension is in config.UPLOAD_EXTS.
  3. Do not cache or reuse leases across sessions; re-request after expiry errors.

Example fix

// before
body: { nativePathLease: filePath } // raw path, no lease -> 400
// after
const lease = await bridge.requestLease(filePath, { kind: 'attachment', operation: 'attach' });
body: { nativePathLease: lease.token }
Defensive patterns

Strategy: validation

Validate before calling

const lease = await bridge.requestLease(path, { kind: 'attachment', operation: 'attach', pathType: 'file' });
if (!lease?.token) throw new Error('no lease granted');

Try / catch

if (res.status === 400 && /Native path grant/.test(detail)) { re_request_lease(path); }

Prevention

When it happens

Trigger: Calling the attach endpoint with a native_path_lease that is missing, empty, has a bad signature, names the wrong operation/kind/path-type, points at a file with a disallowed extension, or was issued for a different path or after expiry.

Common situations: Frontend sends the raw path instead of requesting a lease from the desktop bridge; lease expired between selection and upload; replaying an old lease after the file was replaced; mismatch between the lease's granted kind and the endpoint's expectation.

Related errors


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