unslothai/unsloth · error · HTTPException

str(exc)

Error message

str(exc)

What it means

A 400 on POST /api/providers whose detail is the ValueError message from validate_provider_base_url. That function only refuses URLs that can never be a real endpoint: non-http(s) scheme, control characters or backslashes, malformed URL, missing hostname, and cloud metadata endpoints (169.254.169.254 and DNS aliases). Plain http, loopback, LAN hosts, odd ports, query strings and basic-auth userinfo are deliberately allowed for local runtimes like Ollama and vLLM.

Source

Thrown at studio/backend/routes/providers.py:226

        payload.max_output_tokens,
    )

    _validate_provider_auth_contract(
        info,
        encrypted_api_key = payload.encrypted_api_key,
        base_url = payload.base_url,
        models = payload.models,
        updating = False,
    )

    base_url = payload.base_url or info["base_url"]
    # An empty base URL stays allowed (custom/vLLM entries carry none until the
    # user fills one in); anything present is checked before a key is decrypted.
    if 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

    api_key = resolve_provider_api_key_or_400(None, payload.encrypted_api_key)
    provider_id = uuid.uuid4().hex[:16]

    if api_key:
        credential_secrets.get_or_create_credential_encryption_key()
    with current_credential_write(credential):
        providers_db.create_provider(
            id = provider_id,
            provider_type = payload.provider_type,
            display_name = payload.display_name,
            base_url = base_url,
            models = payload.models,
            available_models = payload.available_models,
            max_output_tokens = payload.max_output_tokens,
        )
        try:
            if api_key:

View on GitHub (pinned to 203007d190)

Solutions

  1. Use a full http:// or https:// URL with a hostname, e.g. http://localhost:11434/v1.
  2. Remove backslashes and control characters from the URL.
  3. If you meant to use an internal gateway, use its real http(s) URL — metadata IPs stay blocked by design.

Example fix

# before
base_url = "localhost:11434/v1"      # no scheme
base_url = "https://169.254.169.254"  # metadata
# after
base_url = "http://localhost:11434/v1"
Defensive patterns

Strategy: validation

Validate before calling

function isValidBaseUrl(u) {
  try {
    const parsed = new URL(u);
    if (!/^https?:$/.test(parsed.protocol)) return false;
    if (!parsed.hostname) return false;
    if (/\\|\s|[\x00-\x1f\x7f]/.test(u)) return false;
    if (parsed.hostname === "169.254.169.254" || parsed.hostname.endsWith(".169.254.169.254")) return false;
    return true;
  } catch { return false; }
}
if (base_url && !isValidBaseUrl(base_url)) throw new Error("base_url must be a full http(s) URL with a hostname");

Try / catch

try { await createProvider(body); } catch (e) { if (e.status === 400 && /base URL/i.test(e.detail)) { showFieldError("base_url", e.detail); return; } throw e; }

Prevention

When it happens

Trigger: Creating a provider with base_url like 'ftp://x', 'file:///etc', 'https://', containing backslashes or control chars, or pointing at 169.254.169.254 / a hostname resolving to it (SSRF guard).

Common situations: Copy-pasting a docs URL with a trailing path typo; attempting to reach cloud metadata as an 'endpoint'; Windows-style paths with backslashes; missing scheme.

Related errors


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