BerriAI/litellm · error · ValueError

api_base is required for Azure WebSocket

Error message

api_base is required for Azure WebSocket

What it means

Azure Responses over WebSocket targets <api_base>/openai/v1/responses (scheme rewritten to wss/ws, model sent in the response.create body). This method requires api_base to build that URL; if api_base is None it raises ValueError before any parsing or connection. Existing /openai/responses or /openai/v1/responses suffixes in the base are stripped, so the root resource URL is the expected input.

Source

Thrown at litellm/llms/azure/responses/transformation.py:189

            route="/openai/responses",
            default_api_version=AZURE_DEFAULT_RESPONSES_API_VERSION,
        )

    def supports_native_websocket(self) -> bool:
        return True

    def get_websocket_url(
        self,
        api_base: str | None,
        litellm_params: dict,
    ) -> str:
        """
        Azure Responses WebSocket endpoint is at /openai/v1/responses with no
        api-version query param. Auth is via Authorization header, model is sent
        in the response.create body — not the URL.
        """
        if api_base is None:
            raise ValueError("api_base is required for Azure WebSocket")

        parsed_url: Final = httpx.URL(api_base)
        path = parsed_url.path.rstrip("/")
        # Strip existing /openai/responses path if the api_base already contains it
        for suffix in ("/openai/v1/responses", "/openai/responses"):
            if path.endswith(suffix):
                path = path[: -len(suffix)]
                break
        scheme: Final = "wss" if parsed_url.scheme == "https" else "ws"
        return str(parsed_url.copy_with(scheme=scheme, path=f"{path}/openai/v1/responses", query=None))

    def model_in_websocket_url(self) -> bool:
        # Azure sends the model in the response.create body, not the URL
        return False

    #########################################################
    ########## DELETE RESPONSE API TRANSFORMATION ##############
    #########################################################

View on GitHub (pinned to 6c2dcb801b)

Solutions

  1. Pass api_base='https://<resource>.openai.azure.com' to the responses WebSocket call.
  2. Add api_base to the Azure model's litellm_params so it reaches get_websocket_url.
  3. Or set the AZURE_API_BASE environment variable if your integration resolves the base from env.
  4. Do not pre-append /openai/v1/responses to the base — the handler constructs the path itself.

Example fix

# before
url = transformation.get_websocket_url(None, litellm_params={})  # raises

# after
url = transformation.get_websocket_url('https://myresource.openai.azure.com', litellm_params={})
# -> 'wss://myresource.openai.azure.com/openai/v1/responses'
Defensive patterns

Strategy: validation

Validate before calling

def validate_responses_ws_base(api_base: str | None, litellm_params: dict) -> str:
    base = api_base or litellm_params.get('api_base')
    if not base:
        raise ValueError('Azure Responses WebSocket requires api_base (resource root URL)')
    return base

Try / catch

try:
    url = transformation.get_websocket_url(api_base, litellm_params)
except ValueError as e:
    if 'api_base is required' in str(e):
        raise ValueError('set api_base to https://<resource>.openai.azure.com for responses WS') from e
    raise

Prevention

When it happens

Trigger: Calling get_websocket_url(None, litellm_params) — i.e. invoking Azure Responses streaming-over-WebSocket without an api_base in the call, litellm_params, or ambient config.

Common situations: Adopting the Responses API with configs written for chat completions that omit api_base; per-model config where api_base was placed on a different model entry; environment migrations that drop AZURE_API_BASE.

Related errors


AI-assisted analysis of BerriAI/litellm@6c2dcb801b (2026-08-15). Data as JSON: /api/errors/3740b09fe47bea0e. Report an issue: GitHub.