unslothai/unsloth · error · HTTPException

Invalid or expired API key

Error message

Invalid or expired API key

What it means

HTTP 401 raised on the API-key path when validate_api_key_with_credential(token) returns None, meaning the sk-unsloth-... bearer does not match any stored, current API key credential. The detail text comes from _invalid_api_key_detail(token), which typically distinguishes revoked vs unknown keys. This is the failure clients should treat as 're-create or fix the API key'.

Source

Thrown at studio/backend/auth/authentication.py:267

    return "Invalid or expired API key"


async def _get_current_credential(
    credentials: HTTPAuthorizationCredentials, *, allow_password_change: bool
) -> Tuple[str, Optional[str]]:
    """Validate the bearer and return ``(subject, credential generation)``.

    The generation is the credential version this request actually authenticated
    against. Routes that persist new credentials must bind their write to it, or
    a reset landing mid-request would bless what it just revoked.
    """
    token = credentials.credentials

    # --- API key path (sk-unsloth-...) ---
    if token.startswith(API_KEY_PREFIX):
        verified = validate_api_key_with_credential(token)
        if verified is None:
            raise HTTPException(
                status_code = status.HTTP_401_UNAUTHORIZED,
                detail = _invalid_api_key_detail(token),
            )
        username, secret = verified
        return username, credential_generation(secret)

    # --- JWT path ---
    subject = _decode_subject_without_verification(token)
    if subject is None:
        raise HTTPException(
            status_code = status.HTTP_401_UNAUTHORIZED,
            detail = "Invalid token payload",
        )

    record = get_user_and_secret(subject)
    if record is None:
        raise HTTPException(
            status_code = status.HTTP_401_UNAUTHORIZED,

View on GitHub (pinned to 203007d190)

Solutions

  1. Generate a fresh API key in studio settings and update the client's environment/config.
  2. Confirm the key is sent verbatim: no leading/trailing whitespace, no shell expansion issues, full sk-unsloth-... string.
  3. If the key was recently revoked or reset, re-issue it and update all consumers.
  4. Verify the client points at the same backend instance that stored the key.

Example fix

# before
headers = {"Authorization": "Bearer sk-unsloth-OLD-REVOKED"}

# after
headers = {"Authorization": f"Bearer {os.environ['UNSLOTH_API_KEY']}"}  # freshly generated key
Defensive patterns

Strategy: validation

Validate before calling

import re
assert re.match(r'^sk-unsloth-[A-Za-z0-9_\-]+$', key) and not key.isspace(), 'malformed API key'

Type guard

def is_wellformed_api_key(token: str) -> bool:
    return bool(token) and token.startswith('sk-unsloth-') and len(token) > len('sk-unsloth-')

Try / catch

try:
    call_api(headers=bearer(key))
except HTTPStatusError as e:
    if e.response.status_code == 401:
        key = create_new_api_key_via_ui()  # or prompt the user

Prevention

When it happens

Trigger: Sending Authorization: Bearer sk-unsloth-... where the key was revoked, deleted, regenerated, or typo'd; using a key issued by a different backend instance/database; whitespace or truncation corrupting the header value.

Common situations: Key rotated in the UI but the old key still baked into scripts/env files; copying keys between environments (dev key against prod); the key was reset via credential reset and older clients keep using it.

Related errors


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