unslothai/unsloth · error · NativePathLeaseError

Native path grant secret is invalid.

Error message

Native path grant secret is invalid.

What it means

The lease secret found in the environment is not valid base64url — _b64decode(encoded) raised before any HMAC use. The secret must be base64url-encoded bytes; anything else (raw ASCII, standard base64 with '+'/'/', typos, quoted values) fails here.

Source

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


def _decode_secret() -> bytes:
    global _CACHED_LEASE_SECRET
    if _CACHED_LEASE_SECRET is not None:
        return _CACHED_LEASE_SECRET
    with _SECRET_INIT_LOCK:
        if _CACHED_LEASE_SECRET is not None:
            return _CACHED_LEASE_SECRET
        with _NATIVE_PATH_ENV_LOCK:
            encoded = os.environ.get(LEASE_SECRET_ENV)
            if encoded is None and _SCRUB_SAVED_SECRET is not None:
                encoded = _SCRUB_SAVED_SECRET
        if not encoded:
            raise NativePathLeaseError("Native path grants require the managed desktop backend.")
        try:
            secret = _b64decode(encoded)
        except Exception as exc:
            raise NativePathLeaseError("Native path grant secret is invalid.") from exc
        if len(secret) < _MIN_LEASE_SECRET_BYTES:
            raise NativePathLeaseError("Native path grant secret is invalid.")
        _CACHED_LEASE_SECRET = secret
        return secret


def _split_lease(lease: str) -> tuple[str, str]:
    if not isinstance(lease, str):
        raise NativePathLeaseError("Native path grant has an invalid format.")
    try:
        lease.encode("ascii")
    except UnicodeEncodeError as exc:
        raise NativePathLeaseError("Native path grant has an invalid format.") from exc
    parts = lease.split(".")
    if len(parts) != 2 or not parts[0] or not parts[1]:
        raise NativePathLeaseError("Native path grant has an invalid format.")
    return parts[0], parts[1]

View on GitHub (pinned to 203007d190)

Solutions

  1. Regenerate the secret as base64url of at least 32 random bytes: openssl rand -base64 48 | tr '+/' '-_' | tr -d '=' and set that value.
  2. Make the signing side (Rust shell/dev harness) use the exact same encoded string.
  3. Remove surrounding quotes, whitespace, and newlines when setting the env var.
  4. Note the decode is unpadded-tolerant but urlsafe-alphabet-only — avoid '+' and '/' characters.

Example fix

# before
export UNSLOTH_STUDIO_NATIVE_PATH_LEASE_SECRET='not-base64!!'

# after
export UNSLOTH_STUDIO_NATIVE_PATH_LEASE_SECRET="$(openssl rand -base64 48 | tr '+/' '-_' | tr -d '=')"
Defensive patterns

Strategy: validation

Validate before calling

import base64, os

def secret_env_ok() -> bool:
    raw = os.environ.get("UNSLOTH_STUDIO_NATIVE_PATH_LEASE_SECRET")
    if not raw:
        return False
    try:
        return len(base64.urlsafe_b64decode(raw + "=" * (-len(raw) % 4))) >= 32
    except Exception:
        return False

Prevention

When it happens

Trigger: Setting UNSLOTH_STUDIO_NATIVE_PATH_LEASE_SECRET to a raw random string instead of base64url; including quotes or whitespace/newlines from shell or .env file interpolation; using standard base64 alphabet characters ('+', '/') that urlsafe decoding rejects; or a truncated copy-paste of the encoded value.

Common situations: Hand-rolling dev environments with openssl rand without base64 encoding; .env files that wrap long values across lines; YAML/JSON config that JSON-escapes the value differently; copy-paste from terminal output that inserted line breaks.

Related errors


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