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
- Generate a fresh API key in studio settings and update the client's environment/config.
- Confirm the key is sent verbatim: no leading/trailing whitespace, no shell expansion issues, full sk-unsloth-... string.
- If the key was recently revoked or reset, re-issue it and update all consumers.
- 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
- Store API keys in env/secret managers; rotate by re-issuing and updating all consumers.
- Never assume a previously working key is still valid after a reset or rotation event.
- Send the key verbatim; strip whitespace when reading from config files.
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
- Invalid or expired token
- Invalid token payload
- Local (stdio) MCP servers can only be configured from the Un
- GitHub {endpoint} returned {r.status_code} {r.reason}. Token
- Password change required
AI-assisted analysis of unslothai/unsloth@203007d190 (2026-08-15).
Data as JSON: /api/errors/2f3bf5d10e19c53d.
Report an issue: GitHub.