{"record":{"id":"e9533921d426abed","repo":"unslothai/unsloth","slug":"provider-base-url-is-required","errorCode":null,"errorMessage":"Provider base URL is required.","messagePattern":"Provider base URL is required\\.","errorType":"validation","errorClass":"ValueError","httpStatus":400,"severity":"error","filePath":"studio/backend/core/inference/providers.py","lineNumber":870,"sourceCode":"\n\ndef validate_provider_base_url(base_url: str) -> str:\n    \"\"\"Return a normalized provider base URL, or raise ``ValueError``.\n\n    The backend issues outbound requests to this URL with the caller's decrypted\n    API key attached, so it is caller-controlled server-side egress. Only shapes\n    that can never be a real provider endpoint are refused: a non-http(s) scheme,\n    control characters, a missing host, and cloud metadata services. Plain http,\n    loopback, LAN hosts, odd ports, query strings and basic-auth userinfo all\n    stay valid -- Ollama, llama.cpp, vLLM and custom gateways rely on them. A\n    caller-supplied hostname is resolved far enough to apply the metadata block\n    to DNS aliases of it; rejecting other private addresses stays opt-in.\n\n    Normalization is strip + trailing-slash removal only (what the client did\n    before), so validating an already-validated URL returns it unchanged.\n    \"\"\"\n    if not isinstance(base_url, str) or not base_url.strip():\n        raise ValueError(\"Provider base URL is required.\")\n\n    raw = base_url.strip()\n    if any(char.isspace() or ord(char) < 32 or ord(char) == 127 for char in raw) or \"\\\\\" in raw:\n        raise ValueError(\"Provider base URL contains invalid characters.\")\n\n    try:\n        parts = urlsplit(raw)\n        port = parts.port\n        hostname = parts.hostname\n    except ValueError as exc:\n        raise ValueError(\"Provider base URL is malformed.\") from exc\n\n    scheme = parts.scheme.lower()\n    if scheme not in (\"http\", \"https\"):\n        raise ValueError(\"Provider base URL must use http or https.\")\n    # Userinfo stays allowed for gateways behind basic auth; the checks below read\n    # the parsed hostname, so http://api.openai.com@169.254.169.254/ is caught.\n    if not hostname:","sourceCodeStart":852,"sourceCodeEnd":888,"githubUrl":"https://github.com/unslothai/unsloth/blob/203007d19051dcd2ae33876786d117c99f6b0368/studio/backend/core/inference/providers.py#L852-L888","documentation":"Simplest validation failure in validate_provider_base_url: the value is not a non-empty string after strip. The API requires a base URL to build any provider request, so an empty/None input is refused before any parsing.","triggerScenarios":"Creating or updating a provider record with base_url None, \"\", or whitespace-only; a form submitted without the URL field; a config loader passing an unset variable.","commonSituations":"Frontend form not requiring the URL field before submit; env var for a custom provider missing; defaulted dict field never filled.","solutions":["Provide the actual provider base URL, e.g. https://api.openai.com/v1.","Make the field required in the UI/form before calling the API.","Default from a known-good constant when the env var is absent."],"exampleFix":"# before\nvalidate_provider_base_url(os.environ.get(\"PROVIDER_URL\"))\n# after\nurl = os.environ.get(\"PROVIDER_URL\") or \"https://api.openai.com/v1\"\nvalidate_provider_base_url(url)","handlingStrategy":"validation","validationCode":"if not isinstance(base_url, str) or not base_url.strip():\n    raise ValueError(\"base URL is required\")  # before calling the API","typeGuard":"def has_base_url(v) -> bool:\n    return isinstance(v, str) and bool(v.strip())","tryCatchPattern":null,"preventionTips":["Make the URL field required in forms.","Default missing env-provided URLs to a known-good constant."],"tags":["validation","provider-config","input"],"backgroundTag":null,"analyzedSha":"203007d19051dcd2ae33876786d117c99f6b0368","analyzedAt":"2026-08-15T02:48:39.846Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}