BerriAI/litellm · error · LassoGuardrailMissingSecrets
Invalid API key
Error message
Invalid API key
What it means
Raised as LassoGuardrailMissingSecrets when the Lasso API responds with HTTP 401, i.e. the lasso-api-key header sent by the guardrail was rejected. Despite the class name (chosen because litellm maps it to a missing/invalid-secret condition), it means authentication failed — the key is wrong, revoked, or from another workspace — not necessarily that it is absent (a fully absent key is caught earlier in _prepare_headers).
Solutions
- Regenerate the key in the Lasso dashboard and update LASSO_API_KEY in the environment of the process running litellm proxy, then restart it.
- Print/verify the exact key the running process sees (e.g. printenv LASSO_API_KEY inside the container) to catch truncation, quotes, or trailing whitespace.
- Confirm the key belongs to the same Lasso workspace/environment as the API endpoint the guardrail calls.
- If you pass lasso_api_key via config.yaml, make sure the os.environ/LASSO_API_KEY reference resolves at proxy startup.
Example fix
# before (.env — truncated/typo'd key) LASSO_API_KEY=lasso_sk_abc123... # after LASSO_API_KEY=lasso_sk_full_valid_key_from_lasso_dashboard
Defensive patterns
Strategy: validation
Validate before calling
# Startup: fail fast if the key is absent before the first guarded request
import os
def validate_lasso_key() -> None:
key = os.environ.get("LASSO_API_KEY")
assert key, "LASSO_API_KEY is not set — set it before enabling the lasso guardrail"
assert not key.strip() != key, "LASSO_API_KEY has leading/trailing whitespace"
assert len(key) > 20, "LASSO_API_KEY looks truncated" Type guard
from litellm.proxy.guardrails.guardrail_hooks.lasso.lasso import LassoGuardrailMissingSecrets
def is_invalid_lasso_key(err: Exception) -> bool:
"""True when Lasso rejected the key (401) — not a transient failure."""
return isinstance(err, LassoGuardrailMissingSecrets) and "Invalid API key" in str(err) Try / catch
from litellm.proxy.guardrails.guardrail_hooks.lasso.lasso import LassoGuardrailMissingSecrets
try:
result = await guardrail_hook(data)
except LassoGuardrailMissingSecrets as e:
# Credential problem: NEVER retry; page the operator and fail closed
if "Invalid API key" in str(e):
raise RuntimeError("Lasso rejected LASSO_API_KEY — rotate the key") from e
raise Prevention
- Store LASSO_API_KEY in a secrets manager and inject it at deploy time, not in checked-in files.
- Add validate_lasso_key() to proxy startup so a bad key fails the boot, not live traffic.
- Keep a rotation runbook: regenerate in Lasso, update env, restart proxy — old keys eventually 401.
- Never retry on 401 — it burns quota and masks the real fix.
When it happens
Trigger: A guarded request reaches _prepare_headers with a non-empty key (from LASSO_API_KEY or lasso_api_key in config), the lasso-api-key header is sent to the Lasso API, and Lasso returns status 401, which httpx surfaces as HTTPStatusError and this handler maps to LassoGuardrailMissingSecrets('Invalid API key').
Common situations: Typo'd or truncated LASSO_API_KEY value (often from a .env file with quotes/whitespace or a line-wrap); the key was rotated or revoked in the Lasso dashboard but the proxy still runs the old one; using a key from a different Lasso workspace/environment (staging vs prod); the env var was set in a different shell than the one launching litellm.
Understand the failure class
- Authentication and authorization failures — expired tokens, bad credentials, and missing scopes.
Related errors
- Authentication failed. Check your Arize Phoenix API key and…
- Microsoft Purview DLP: No proxy-authenticated user…
- API error
- api_key is required
- API key is required
AI-assisted analysis of BerriAI/litellm@77b7c6c40c (2026-08-18).
Data as JSON: /api/errors/1c1b7aab8c361ed3.
Report an issue: GitHub.
Appendix: source
Thrown at litellm/proxy/guardrails/guardrail_hooks/lasso/lasso.py:614
# Log error with context
verbose_proxy_logger.error(
"Error calling Lasso API: %s",
error,
extra={
"guardrail_name": getattr(self, "guardrail_name", "unknown"),
"message_type": message_type,
"error_type": type(error).__name__,
},
)
# Handle specific error types if httpx is available
if HTTPX_AVAILABLE:
if isinstance(error, httpx.TimeoutException):
raise LassoGuardrailAPIError("Lasso API timeout")
elif isinstance(error, httpx.HTTPStatusError):
if error.response.status_code == 401:
raise LassoGuardrailMissingSecrets("Invalid API key")
elif error.response.status_code == 429:
raise LassoGuardrailAPIError("Lasso API rate limit exceeded")
else:
raise LassoGuardrailAPIError(f"API error: {error.response.status_code}")
# Generic error handling
raise LassoGuardrailAPIError(f"Failed to verify request safety with Lasso API: {error}")
def _log_masking_applied(
self,
message_type: Literal["PROMPT", "COMPLETION"],
response: dict[str, Any],
) -> None:
"""Log masking application with structured context."""
conversation_id: Final = getattr(self, "conversation_id", "unknown")
verbose_proxy_logger.debug(
"Lasso masking applied",
extra={View on GitHub (pinned to 77b7c6c40c)