BerriAI/litellm · critical · CatoNetworksGuardrailMissingSecrets

Couldn't get Cato Networks api key, either set the `CATO_API

Error message

Couldn't get Cato Networks api key, either set the `CATO_API_KEY` in the environment or pass it as a parameter to the guardrail in the config file

What it means

CatoNetworksGuardrailMissingSecrets is raised from the Cato Networks guardrail constructor when neither the api_key parameter nor the CATO_API_KEY environment variable yields a key. It is a fail-fast startup error: the guardrail cannot authenticate to the Cato AI Security API (api.aisec.catonetworks.com by default), so initialization aborts rather than silently allowing unscanned traffic.

Source

Thrown at litellm/proxy/guardrails/guardrail_hooks/cato_networks/cato_networks.py:115

            GuardrailEventHooks.pre_call,
            GuardrailEventHooks.during_call,
            GuardrailEventHooks.post_call,
        ]

    def __init__(self, api_key: str | None = None, api_base: str | None = None, **kwargs):
        kwargs.setdefault("supported_event_hooks", list(self.get_supported_event_hooks()))
        ssl_verify: Final = kwargs.pop("ssl_verify", None)
        self.async_handler = get_async_httpx_client(
            llm_provider=httpxSpecialProvider.GuardrailCallback,
            params={"ssl_verify": ssl_verify} if ssl_verify is not None else None,
        )
        self.api_key = api_key or os.environ.get("CATO_API_KEY")
        if not self.api_key:
            msg: Final = (
                "Couldn't get Cato Networks api key, either set the `CATO_API_KEY` in the environment or "
                "pass it as a parameter to the guardrail in the config file"
            )
            raise CatoNetworksGuardrailMissingSecrets(msg)
        self.api_base = api_base or os.environ.get("CATO_API_BASE") or "https://api.aisec.catonetworks.com"
        self.api_base = self.api_base.rstrip("/")
        self.ws_api_base = self.api_base.replace("http://", "ws://").replace("https://", "wss://")
        self._ws_connect_ssl_kwargs = self._build_ws_ssl_kwargs(ssl_verify, self.ws_api_base)
        super().__init__(**kwargs)

    @staticmethod
    def _build_ws_ssl_kwargs(ssl_verify: bool | str | None, ws_api_base: str) -> _WsSslKwargs:
        """Resolve the ``ssl`` argument for ``websockets.connect``. Mirrors the
        ``ssl_verify`` handling applied to the HTTP handler so a custom Cato instance
        behind TLS honours the same verification settings for streaming."""
        if ssl_verify is None or not ws_api_base.startswith("wss://"):
            return {}
        ssl_config = get_ssl_configuration(ssl_verify)
        if ssl_config is False:
            ssl_config = ssl.create_default_context()
            ssl_config.check_hostname = False
            ssl_config.verify_mode = ssl.CERT_NONE

View on GitHub (pinned to 77b7c6c40c)

Solutions

  1. Set CATO_API_KEY in the environment the proxy actually runs in (systemd Environment=, docker env, .env loaded by the proxy).
  2. Or pass api_key directly (or via <secret_manager> reference) in the guardrail's litellm_params.
  3. Verify with a quick check before startup: printenv CATO_API_KEY or litellm's secret resolution test.
  4. Restart/reload the proxy after the env change — the check runs at guardrail init, not per request.

Example fix

# before
guardrails:
  - guardrail_name: cato
    litellm_params:
      guardrail: cato_networks

# after — explicit key via environment
#   export CATO_API_KEY=xxxx  (in the service env)
guardrails:
  - guardrail_name: cato
    litellm_params:
      guardrail: cato_networks
      api_key: os.environ/CATO_API_KEY
Defensive patterns

Strategy: validation

Validate before calling

import os
from litellm import get_secret_str
key = get_secret_str("CATO_API_KEY") or os.environ.get("CATO_API_KEY")
if not key:
    raise SystemExit("Set CATO_API_KEY before starting the litellm proxy")

Prevention

When it happens

Trigger: Adding a cato_networks guardrail to config.yaml without api_key in litellm_params while the proxy process environment lacks CATO_API_KEY; deploying via Docker/systemd where the env var is set in a shell but not in the service unit; secrets referenced with the wrong secret manager path so get_secret resolves to None.

Common situations: Env var set in an interactive shell but the proxy runs under a different user/service; typos in the variable name (CATO_APIKEY, CATO_TOKEN); key stored in litellm's secret_manager but the guardrail only reads the literal env var and the api_key param.

Related errors


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