BerriAI/litellm · error · Exception

Error updating key: {response_text}

Error message

Error updating key: {response_text}

What it means

KeysManagementClient.update() wraps every failure of POST {base_url}/key/update in a bare Exception whose message is 'Error updating key: ' + the raw response body — or the literal 'Error updating key: None' when no response exists (connection refused, DNS failure, timeout). Unlike its sibling methods it catches Exception rather than HTTPError, so all type information is lost: a 401 that would elsewhere become UnauthorizedError surfaces here as this generic exception, and the original traceback is discarded because the raise uses no `from`. To diagnose, you must read the server text embedded in the message.

Source

Thrown at litellm/proxy/client/keys.py:287

            data["team_id"] = team_id
        if models is not None:
            data["models"] = models
        if spend is not None:
            data["spend"] = spend
        if duration is not None:
            data["duration"] = duration
        if aliases is not None:
            data["aliases"] = aliases
        request: Final = requests.Request("POST", url, headers=self._get_headers(), json=data)
        session: Final = requests.Session()
        response_text: str | None = None
        try:
            response: Final = session.send(request.prepare())
            response_text = response.text
            response.raise_for_status()
            return response.json()
        except Exception:
            raise Exception(f"Error updating key: {response_text}")

    def info(self, key: str, return_request: bool = False) -> dict[str, Any] | requests.Request:
        """
        Get information about API keys.

        Args:
            key (str): The key hash to get information about
            return_request (bool): If True, returns the prepared request object instead of executing it

        Returns:
            Union[Dict[str, Any], requests.Request]: Either the response from the server or a prepared request object if return_request is True

        Raises:
            UnauthorizedError: If the request fails with a 401 status code
            requests.exceptions.RequestException: If the request fails with any other error
        """
        url: Final = f"{self._base_url}/key/info?key={key}"
        request: Final = requests.Request("GET", url, headers=self._get_headers())

View on GitHub (pinned to 77b7c6c40c)

Solutions

  1. Read the text after the prefix — the proxy's actual error (e.g.{"error":"Key does not exist in proxy"}) tells you whether it's auth, missing key, or validation
  2. Pre-verify the key with keys.info(key=...) (which raises typed UnauthorizedError/HTTPError) and confirm you pass the key hash, not the alias
  3. If the message ends with 'None', the request never got a response: check the proxy is running and base_url/port are correct
  4. Catch this Exception narrowly around update() and re-raise a typed error, since the library discards the original

Example fix

# before
keys.update(key="sk-123", spend=100)  # Exception: Error updating key: {"error": "Key does not exist in proxy"}

# after
from litellm.proxy.client.exceptions import UnauthorizedError
try:
    keys.info(key="sk-123")  # typed pre-check: raises UnauthorizedError on bad creds
    keys.update(key="sk-123", spend=100)
except Exception as e:
    raise RuntimeError(f"key update failed: {e}") from e
Defensive patterns

Strategy: validation

Validate before calling

from litellm.proxy.client.keys import KeysManagementClient

def update_key_if_exists(keys: KeysManagementClient, key: str, **fields) -> dict:
    keys.info(key=key)  # typed pre-check: raises UnauthorizedError for bad creds, HTTPError 404 if gone
    return keys.update(key=key, **fields)

Try / catch

try:
    keys.update(key=key, spend=new_spend)
except Exception as e:  # update() raises a bare Exception — cannot narrow further
    msg = str(e)
    if msg.endswith("None"):
        raise RuntimeError("proxy unreachable (no HTTP response)") from e
    raise RuntimeError(f"key update rejected by proxy: {msg}") from e

Prevention

When it happens

Trigger: Updating a key hash that no longer exists (400/404 body inline in the message); proxy unreachable or base_url wrong ('Error updating key: None'); auth rejected (401 body inline); server rejecting duration/spend/models values (400/422 body inline); passing a key alias where the hash is expected.

Common situations: Key deleted on the proxy between fetch and update; network flake or wrong port in base_url; rotated admin key; scripts assuming typed exceptions (UnauthorizedError) around update() and missing this generic one.

Related errors


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