{"record":{"id":"576b7c2a7f13b863","repo":"unslothai/unsloth","slug":"str-exc-576b7c","errorCode":null,"errorMessage":"str(exc)","messagePattern":"str\\(exc\\)","errorType":"http","errorClass":"HTTPException","httpStatus":400,"severity":"error","filePath":"studio/backend/routes/providers.py","lineNumber":226,"sourceCode":"        payload.max_output_tokens,\n    )\n\n    _validate_provider_auth_contract(\n        info,\n        encrypted_api_key = payload.encrypted_api_key,\n        base_url = payload.base_url,\n        models = payload.models,\n        updating = False,\n    )\n\n    base_url = payload.base_url or info[\"base_url\"]\n    # An empty base URL stays allowed (custom/vLLM entries carry none until the\n    # user fills one in); anything present is checked before a key is decrypted.\n    if base_url:\n        try:\n            base_url = validate_provider_base_url(base_url)\n        except ValueError as exc:\n            raise HTTPException(status_code = 400, detail = str(exc)) from None\n\n    api_key = resolve_provider_api_key_or_400(None, payload.encrypted_api_key)\n    provider_id = uuid.uuid4().hex[:16]\n\n    if api_key:\n        credential_secrets.get_or_create_credential_encryption_key()\n    with current_credential_write(credential):\n        providers_db.create_provider(\n            id = provider_id,\n            provider_type = payload.provider_type,\n            display_name = payload.display_name,\n            base_url = base_url,\n            models = payload.models,\n            available_models = payload.available_models,\n            max_output_tokens = payload.max_output_tokens,\n        )\n        try:\n            if api_key:","sourceCodeStart":208,"sourceCodeEnd":244,"githubUrl":"https://github.com/unslothai/unsloth/blob/203007d19051dcd2ae33876786d117c99f6b0368/studio/backend/routes/providers.py#L208-L244","documentation":"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.","triggerScenarios":"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).","commonSituations":"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.","solutions":["Use a full http:// or https:// URL with a hostname, e.g. http://localhost:11434/v1.","Remove backslashes and control characters from the URL.","If you meant to use an internal gateway, use its real http(s) URL — metadata IPs stay blocked by design."],"exampleFix":"# before\nbase_url = \"localhost:11434/v1\"      # no scheme\nbase_url = \"https://169.254.169.254\"  # metadata\n# after\nbase_url = \"http://localhost:11434/v1\"","handlingStrategy":"validation","validationCode":"function isValidBaseUrl(u) {\n  try {\n    const parsed = new URL(u);\n    if (!/^https?:$/.test(parsed.protocol)) return false;\n    if (!parsed.hostname) return false;\n    if (/\\\\|\\s|[\\x00-\\x1f\\x7f]/.test(u)) return false;\n    if (parsed.hostname === \"169.254.169.254\" || parsed.hostname.endsWith(\".169.254.169.254\")) return false;\n    return true;\n  } catch { return false; }\n}\nif (base_url && !isValidBaseUrl(base_url)) throw new Error(\"base_url must be a full http(s) URL with a hostname\");","typeGuard":null,"tryCatchPattern":"try { await createProvider(body); } catch (e) { if (e.status === 400 && /base URL/i.test(e.detail)) { showFieldError(\"base_url\", e.detail); return; } throw e; }","preventionTips":["Always include the scheme (http:// or https://) in base URLs.","Local runtimes (Ollama, vLLM, llama.cpp) work with http:// and loopback/LAN hosts — no need to fake https.","Never target cloud metadata IPs; they are blocked as SSRF protection."],"tags":["base-url","ssrf","validation","providers"],"backgroundTag":null,"analyzedSha":"203007d19051dcd2ae33876786d117c99f6b0368","analyzedAt":"2026-08-15T02:48:39.846Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}