{"record":{"id":"1d2baeb36a70a2a3","repo":"BerriAI/litellm","slug":"invalid-oci-region-region-r-must-match-a-z-a","errorCode":null,"errorMessage":"Invalid OCI region {region!r}: must match ^[a-z][a-z0-9-]{{0,30}}[a-z0-9]$ (e.g. 'us-ashburn-1').","messagePattern":"Invalid OCI region (.+?): must match \\^\\[a-z\\]\\[a-z0-9-\\](.+?)\\}\\[a-z0-9\\]\\$ \\(e\\.g\\. 'us-ashburn-1'\\)\\.","errorType":"exception","errorClass":"OCIError","httpStatus":400,"severity":"error","filePath":"litellm/llms/oci/common_utils.py","lineNumber":192,"sourceCode":"\n\n_OCI_REGION_RE: Final = re.compile(r\"^[a-z][a-z0-9-]{0,30}[a-z0-9]$\")\n_OCI_ACTION_PATH_RE: Final = re.compile(rf\"/{OCI_API_VERSION}/actions/[^/?#]+/?$\")\n\n\ndef get_oci_base_url(optional_params: dict, api_base: str | None = None) -> str:\n    \"\"\"Return the OCI inference base URL, respecting any explicit api_base override.\n\n    If ``api_base`` already ends with a fully-formed OCI action path\n    (``/{OCI_API_VERSION}/actions/<name>``), that suffix is stripped so callers\n    can append their own action path without producing a doubled URL.\n    \"\"\"\n    if api_base:\n        return _OCI_ACTION_PATH_RE.sub(\"\", api_base).rstrip(\"/\")\n    creds: Final = resolve_oci_credentials(optional_params)\n    region: Final = creds[\"oci_region\"]\n    if not isinstance(region, str) or not _OCI_REGION_RE.match(region):\n        raise OCIError(\n            status_code=400,\n            message=(\n                f\"Invalid OCI region {region!r}: must match ^[a-z][a-z0-9-]{{0,30}}[a-z0-9]$ (e.g. 'us-ashburn-1').\"\n            ),\n        )\n    return f\"https://inference.generativeai.{region}.oci.oraclecloud.com\"\n\n\n# ---------------------------------------------------------------------------\n# Signing implementations (shared by chat, embed, and rerank configs)\n# ---------------------------------------------------------------------------\n\n\ndef sign_with_oci_signer(\n    headers: dict,\n    optional_params: dict,\n    request_data: dict,\n    api_base: str,","sourceCodeStart":174,"sourceCodeEnd":210,"githubUrl":"https://github.com/BerriAI/litellm/blob/6c2dcb801bf2b75c18f1bb24140e7cf57465cc4d/litellm/llms/oci/common_utils.py#L174-L210","documentation":"get_oci_base_url validates the resolved OCI region against ^[a-z][a-z0-9-]{0,30}[a-z0-9]$ before building https://inference.generativeai.<region>.oci.oraclecloud.com. An invalid region (wrong type, uppercase, underscores, spaces, or a full URL pasted as a region) raises OCIError(400) with the regex and an example.","triggerScenarios":"OCI_REGION / oci_region set to 'us-ashburn-1 ' (trailing space), 'US-Ashburn-1', 'us_ashburn_1', None, an empty string, or a whole endpoint URL like 'https://inference.generativeai...'; also a numeric-only or 40+ char region string.","commonSituations":"Region copied from an OCI Console URL that includes extra fragments; environment variables with trailing whitespace/newlines from .env files or Helm values; passing a full endpoint where a region short code is expected; CI injecting a quoted value with spaces.","solutions":["Set a valid three-part region identifier: us-ashburn-1, eu-frankfurt-1, uk-london-1, ap-tokyo-1, etc.","Trim the env value: region.strip().lower() before setting OCI_REGION.","If you actually want a custom endpoint, pass it as api_base instead of as the region.","Verify with: echo \"$OCI_REGION\" | cat -A to reveal hidden whitespace."],"exampleFix":"# before\nos.environ[\"OCI_REGION\"] = \"US-Ashburn-1 \"  # OCIError(400)\n\n# after\nimport os, re\nregion = os.environ.get(\"OCI_REGION\", \"\").strip().lower()\nassert re.match(r\"^[a-z][a-z0-9-]{0,30}[a-z0-9]$\", region), f\"bad region: {region!r}\"\nos.environ[\"OCI_REGION\"] = region","handlingStrategy":"validation","validationCode":"import os, re\nregion = os.environ.get(\"OCI_REGION\", \"\").strip().lower()\nif not re.match(r\"^[a-z][a-z0-9-]{0,30}[a-z0-9]$\", region):\n    raise ValueError(f\"Invalid OCI region: {region!r} — expected e.g. 'us-ashburn-1'\")","typeGuard":"import re\n\ndef is_valid_oci_region(region: object) -> bool:\n    return isinstance(region, str) and bool(re.match(r\"^[a-z][a-z0-9-]{0,30}[a-z0-9]$\", region))","tryCatchPattern":"from litellm.llms.oci.common_utils import OCIError\ntry:\n    litellm.completion(model=\"oci/...\", messages=m)\nexcept OCIError as e:\n    if e.status_code == 400 and \"Invalid OCI region\" in str(e):\n        fix_region_config()\n    raise","preventionTips":["Normalize OCI_REGION at load time: strip().lower().","Use api_base for custom endpoints, never the region field.","Add schema validation for OCI_* env vars at app startup."],"tags":["oci","configuration","validation","region"],"backgroundTag":null,"analyzedSha":"6c2dcb801bf2b75c18f1bb24140e7cf57465cc4d","analyzedAt":"2026-08-15T07:12:03.035Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}