BerriAI/litellm · error · ValueError

Unsupported HTTP method: {method}

Error message

Unsupported HTTP method: {method}

What it means

ValueError raised by the sandbox's http_request primitive when the method argument is not exactly one of GET, POST, PUT, DELETE, PATCH (uppercase, case-sensitive). The custom-code guardrail deliberately exposes a minimal HTTP surface; any other method — HEAD, OPTIONS, or lowercase 'get' — is rejected before any network call is made.

Source

Thrown at litellm/proxy/guardrails/guardrail_hooks/custom_code/primitives.py:511

    headers: dict[str, str] | None,
    body: Any | None,
    timeout: float,
) -> httpx.Response:
    """Execute the HTTP request using the appropriate client method."""
    json_body, data_body = _prepare_http_body(body)

    if method == "GET":
        return await client.get(url=url, headers=headers)
    elif method == "POST":
        return await client.post(url=url, headers=headers, json=json_body, data=data_body, timeout=timeout)
    elif method == "PUT":
        return await client.put(url=url, headers=headers, json=json_body, data=data_body, timeout=timeout)
    elif method == "DELETE":
        return await client.delete(url=url, headers=headers, json=json_body, data=data_body, timeout=timeout)
    elif method == "PATCH":
        return await client.patch(url=url, headers=headers, json=json_body, data=data_body, timeout=timeout)
    else:
        raise ValueError(f"Unsupported HTTP method: {method}")


async def http_get(
    url: str,
    headers: dict[str, str] | None = None,
    timeout: float | None = None,
) -> dict[str, Any]:
    """
    Make an async HTTP GET request.

    Convenience wrapper around http_request for GET requests.

    Args:
        url: The URL to request
        headers: Optional dict of HTTP headers
        timeout: Optional timeout in seconds

    Returns:

View on GitHub (pinned to 77b7c6c40c)

Solutions

  1. Use one of the five supported uppercase methods: GET, POST, PUT, DELETE, PATCH
  2. Substitute HEAD with GET and ignore the response body
  3. Prefer the convenience wrappers the sandbox exposes (http_get, http_post) which fix the method for you

Example fix

# before
resp = await http_request('HEAD', 'https://api.example.com/health')

# after
resp = await http_get('https://api.example.com/health')
Defensive patterns

Strategy: type-guard

Validate before calling

_SUPPORTED = {'GET', 'POST', 'PUT', 'DELETE', 'PATCH'}

method = (method or 'GET').upper()
if method not in _SUPPORTED:
    raise ValueError(f'use one of {sorted(_SUPPORTED)}; got {method!r}')
resp = await http_request(method, url, json_body=payload)

Type guard

def is_supported_http_method(method: object) -> bool:
    return isinstance(method, str) and method in {'GET', 'POST', 'PUT', 'DELETE', 'PATCH'}

Try / catch

try:
    resp = await http_request(method, url)
except ValueError as e:
    if 'Unsupported HTTP method' in str(e):
        resp = await http_get(url)  # fall back to the supported surface
    else:
        raise

Prevention

When it happens

Trigger: Custom code calls http_request('HEAD', url) for a health probe, http_request('get', url) with wrong case, or 'OPTIONS' to probe CORS support; the dispatch chain falls through to the else branch and raises.

Common situations: Porting code that used requests/httpx directly where methods are case-insensitive; method strings sourced from config that arrive lowercase; HEAD-style health checks.

Related errors


AI-assisted analysis of BerriAI/litellm@77b7c6c40c (2026-08-18). Data as JSON: /api/errors/4d8906771e761912. Report an issue: GitHub.