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

  1. Omit encrypted_api_key entirely to keep the current key.
  2. Send clear_api_key: true (alone) to delete the stored key.
  3. 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

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


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