{"record":{"id":"1c1b7aab8c361ed3","repo":"BerriAI/litellm","slug":"invalid-api-key","errorCode":null,"errorMessage":"Invalid API key","messagePattern":"Invalid API key","errorType":"exception","errorClass":"LassoGuardrailMissingSecrets","httpStatus":null,"severity":"error","filePath":"litellm/proxy/guardrails/guardrail_hooks/lasso/lasso.py","lineNumber":614,"sourceCode":"\n        # Log error with context\n        verbose_proxy_logger.error(\n            \"Error calling Lasso API: %s\",\n            error,\n            extra={\n                \"guardrail_name\": getattr(self, \"guardrail_name\", \"unknown\"),\n                \"message_type\": message_type,\n                \"error_type\": type(error).__name__,\n            },\n        )\n\n        # Handle specific error types if httpx is available\n        if HTTPX_AVAILABLE:\n            if isinstance(error, httpx.TimeoutException):\n                raise LassoGuardrailAPIError(\"Lasso API timeout\")\n            elif isinstance(error, httpx.HTTPStatusError):\n                if error.response.status_code == 401:\n                    raise LassoGuardrailMissingSecrets(\"Invalid API key\")\n                elif error.response.status_code == 429:\n                    raise LassoGuardrailAPIError(\"Lasso API rate limit exceeded\")\n                else:\n                    raise LassoGuardrailAPIError(f\"API error: {error.response.status_code}\")\n\n        # Generic error handling\n        raise LassoGuardrailAPIError(f\"Failed to verify request safety with Lasso API: {error}\")\n\n    def _log_masking_applied(\n        self,\n        message_type: Literal[\"PROMPT\", \"COMPLETION\"],\n        response: dict[str, Any],\n    ) -> None:\n        \"\"\"Log masking application with structured context.\"\"\"\n        conversation_id: Final = getattr(self, \"conversation_id\", \"unknown\")\n        verbose_proxy_logger.debug(\n            \"Lasso masking applied\",\n            extra={","sourceCodeStart":596,"sourceCodeEnd":632,"githubUrl":"https://github.com/BerriAI/litellm/blob/77b7c6c40c0c5aa5fbcb1d6a1825ac39ca8829b8/litellm/proxy/guardrails/guardrail_hooks/lasso/lasso.py#L596-L632","documentation":"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).","triggerScenarios":"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').","commonSituations":"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.","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."],"exampleFix":"# before (.env — truncated/typo'd key)\nLASSO_API_KEY=lasso_sk_abc123...\n\n# after\nLASSO_API_KEY=lasso_sk_full_valid_key_from_lasso_dashboard","handlingStrategy":"validation","validationCode":"# Startup: fail fast if the key is absent before the first guarded request\nimport os\n\ndef validate_lasso_key() -> None:\n    key = os.environ.get(\"LASSO_API_KEY\")\n    assert key, \"LASSO_API_KEY is not set — set it before enabling the lasso guardrail\"\n    assert not key.strip() != key, \"LASSO_API_KEY has leading/trailing whitespace\"\n    assert len(key) > 20, \"LASSO_API_KEY looks truncated\"","typeGuard":"from litellm.proxy.guardrails.guardrail_hooks.lasso.lasso import LassoGuardrailMissingSecrets\n\ndef is_invalid_lasso_key(err: Exception) -> bool:\n    \"\"\"True when Lasso rejected the key (401) — not a transient failure.\"\"\"\n    return isinstance(err, LassoGuardrailMissingSecrets) and \"Invalid API key\" in str(err)","tryCatchPattern":"from litellm.proxy.guardrails.guardrail_hooks.lasso.lasso import LassoGuardrailMissingSecrets\n\ntry:\n    result = await guardrail_hook(data)\nexcept LassoGuardrailMissingSecrets as e:\n    # Credential problem: NEVER retry; page the operator and fail closed\n    if \"Invalid API key\" in str(e):\n        raise RuntimeError(\"Lasso rejected LASSO_API_KEY — rotate the key\") from e\n    raise","preventionTips":["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."],"tags":["authentication","api-key","lasso","guardrails","http-401"],"backgroundTag":"invalid-api-key","analyzedSha":"77b7c6c40c0c5aa5fbcb1d6a1825ac39ca8829b8","analyzedAt":"2026-08-18T11:44:31.656Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}