BerriAI/litellm · error · GraySwanGuardrailAPIError

{exc}

Error message

{exc}

What it means

GraySwanGuardrailAPIError raised at the top of GraySwanGuardrail.apply_guardrail's exception handler when fail_open is False (it defaults to True) and the caught exception is not a guardrail decision (block/passthrough exceptions propagate via _is_grayswan_exception). It re-raises existing GraySwanGuardrailAPIError as-is, or wraps any other exception with its string form and a best-effort status_code. The guardrail failure is logged first via _log_guardrail_failure.

Source

Thrown at litellm/proxy/guardrails/guardrail_hooks/grayswan/grayswan.py:253

                raise
            end_time: Final = time.time()
            status_code: Final = getattr(exc, "status_code", None) or getattr(exc, "exception_status_code", None)
            self._log_guardrail_failure(
                exc=exc,
                request_data=request_data or {},
                start_time=start_time,
                end_time=end_time,
                status_code=status_code,
            )
            if self.fail_open:
                verbose_proxy_logger.warning(
                    "Gray Swan Guardrail: fail_open=True. Allowing request to proceed despite error: %s",
                    exc,
                )
                return inputs
            if isinstance(exc, GraySwanGuardrailAPIError):
                raise exc
            raise GraySwanGuardrailAPIError(str(exc), status_code=status_code) from exc

    def _is_grayswan_exception(self, exc: Exception) -> bool:
        # Guardrail decision (passthrough) should always propagate,
        # regardless of fail_open.
        if isinstance(exc, ModifyResponseException):
            return True
        detail: Final = getattr(exc, "detail", None)
        if isinstance(detail, dict):
            return detail.get("error") == GRAYSWAN_BLOCK_ERROR_MSG
        return False

    # ------------------------------------------------------------------
    # Legacy Test Interface (for backward compatibility)
    # ------------------------------------------------------------------

    async def run_grayswan_guardrail(self, payload: dict) -> dict[str, Any]:
        """
        Run the GraySwan guardrail on a payload.

View on GitHub (pinned to 77b7c6c40c)

Solutions

  1. Check the logged guardrail failure entry for the wrapped cause and status code.
  2. Verify GRAYSWAN_API_KEY / GRAYSWAN_API_BASE and curl the monitor endpoint directly.
  3. Raise guardrail_timeout if slow responses are the cause, or lower it to fail faster.
  4. If availability matters more than strictness for this deployment, keep/set fail_open: true (default) so errors pass traffic through.
  5. Remember block/passthrough decisions always propagate regardless of fail_open — only infrastructure errors are affected.

Example fix

# before
litellm_params:
  guardrail: grayswan
  fail_open: false
  guardrail_timeout: 30

# after
litellm_params:
  guardrail: grayswan
  fail_open: false
  guardrail_timeout: 60
Defensive patterns

Strategy: fallback

Validate before calling

import os
missing = [v for v in ('GRAYSWAN_API_KEY',) if not os.getenv(v)]
if missing:
    raise SystemExit(f'deploy blocked, missing env: {missing}')

Type guard

from litellm.proxy.guardrails.guardrail_hooks.grayswan.grayswan import GraySwanGuardrailAPIError

def is_grayswan_api_error(exc: BaseException) -> bool:
    return isinstance(exc, GraySwanGuardrailAPIError)

Try / catch

from litellm.proxy.guardrails.guardrail_hooks.grayswan.grayswan import GraySwanGuardrailAPIError
try:
    result = await guardrail.apply_guardrail(inputs, request_data, input_type, logging_obj)
except GraySwanGuardrailAPIError as e:
    logger.warning('GraySwan API error, failing open: %s (status=%s)', e, getattr(e, 'status_code', None))
    result = dict(inputs)

Prevention

When it happens

Trigger: fail_open explicitly set to false, and the monitor call fails — network error, timeout beyond guardrail_timeout (default 30s), non-2xx from raise_for_status, JSON decode failure; or any unexpected exception in response processing.

Common situations: Operators setting fail_open: false for strict compliance, then a GraySwan outage or timeout makes every request fail; oversized payloads timing out at the 30s default; auth failures after key rotation.

Related errors


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