unslothai/unsloth · error · HTTPException
API key cannot be empty
Error message
API key cannot be empty
What it means
A 400 from PUT /api/providers/{provider_id}: encrypted_api_key was supplied and decrypted, but the decrypted value was empty. The server treats an explicit-but-empty key as an invalid operation — use clear_api_key to remove a key, not an empty key payload.
Source
Thrown at studio/backend/routes/providers.py:317
# Only a *changed* base URL is validated. The dialog re-sends the stored value
# on every edit, so validating an unchanged legacy row would lock the user out
# of editing its models or API key. Outbound use is still checked.
base_url = payload.base_url
if base_url and base_url != existing["base_url"]:
try:
base_url = validate_provider_base_url(base_url)
except ValueError as exc:
raise HTTPException(status_code = 400, detail = str(exc)) from None
replacement_api_key = None
if payload.encrypted_api_key:
credential_secrets.get_or_create_credential_encryption_key()
replacement_api_key = resolve_provider_api_key_or_400(
provider_id, payload.encrypted_api_key
)
if not replacement_api_key:
raise HTTPException(status_code = 400, detail = "API key cannot be empty")
with current_credential_write(credential):
if metadata_requested:
metadata_updates = dict(
id = provider_id,
display_name = payload.display_name,
base_url = base_url,
is_enabled = payload.is_enabled,
models = payload.models,
available_models = payload.available_models,
)
if max_output_tokens_requested:
metadata_updates["max_output_tokens"] = payload.max_output_tokens
providers_db.update_provider(**metadata_updates)
try:
if replacement_api_key is not None:
credential_secrets.save_provider_api_key(provider_id, replacement_api_key)
elif payload.clear_api_key:View on GitHub (pinned to 203007d190)
Solutions
- Omit encrypted_api_key entirely to keep the current key.
- Send clear_api_key: true (alone) to delete the stored key.
- Only send encrypted_api_key when it decrypts to a non-empty string.
Example fix
// before
body.encrypted_api_key = await encrypt(keyInput.value); // even when ""
// after
if (keyInput.value.trim() !== "") {
body.encrypted_api_key = await encrypt(keyInput.value.trim());
} Defensive patterns
Strategy: validation
Validate before calling
if (typeof keyInput === "string" && keyInput.trim() === "") {
delete body.encrypted_api_key; // blank means keep current key, not replace-with-empty
} Prevention
- Never encrypt and send an empty key string.
- Use clear_api_key alone to remove a stored key.
When it happens
Trigger: Submitting the key field when the user cleared it and the client encrypts the empty string anyway; client code that always includes encrypted_api_key once the field exists.
Common situations: Forms where 'leave blank to keep current' is implemented by sending an encrypted empty string; whitespace-trimmed input becoming empty.
Related errors
- model load did not reach ready
- unknown family '{name}'
- Refused notebook fetch from {host!r}: not in allowlist {sort
- Cell uses shell metacharacters / interpolation but --no-allo
- load error: {backend.load_progress()}
AI-assisted analysis of unslothai/unsloth@203007d190 (2026-08-15).
Data as JSON: /api/errors/766431a2f6f15a8a.
Report an issue: GitHub.