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_NONEView on GitHub (pinned to 77b7c6c40c)
Solutions
- Set CATO_API_KEY in the environment the proxy actually runs in (systemd Environment=, docker env, .env loaded by the proxy).
- Or pass api_key directly (or via <secret_manager> reference) in the guardrail's litellm_params.
- Verify with a quick check before startup: printenv CATO_API_KEY or litellm's secret resolution test.
- 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
- Put secret preflight checks (all guardrail env keys) into the container entrypoint so the process fails before accepting traffic.
- Use docker compose env_file / systemd EnvironmentFile consistently for the proxy service.
- Prefer litellm secret-manager references over raw env vars in config to centralize key management.
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
- Cisco AI Defense API key is required. Set `CISCO_AI_DEFENSE_
- Compresr guardrail requires an API key. Set `api_key` in the
- Block Code Execution guardrail requires a guardrail_name
- CrowdStrike AIDR guardrail name is required
- Bedrock guardrail failed: {e}
AI-assisted analysis of BerriAI/litellm@77b7c6c40c (2026-08-18).
Data as JSON: /api/errors/15610e69f68af70f.
Report an issue: GitHub.