{"record":{"id":"c5ee792da73e9c43","repo":"BerriAI/litellm","slug":"blocked-by-gray-swan-guardrail","errorCode":null,"errorMessage":"Blocked by Gray Swan Guardrail","messagePattern":"Blocked by Gray Swan Guardrail","errorType":"http","errorClass":"HTTPException","httpStatus":400,"severity":"error","filePath":"litellm/proxy/guardrails/guardrail_hooks/grayswan/grayswan.py","lineNumber":344,"sourceCode":"            \"flagged\": True,\n            \"violation_score\": violation_score,\n            \"violated_rules\": violated_rules,\n            \"mutation\": mutation_detected,\n            \"ipi\": ipi_detected,\n        }\n\n        # Determine if this is input (pre-call/during-call) or output (post-call)\n        if hook_type is not None:\n            is_input = hook_type in [\n                GuardrailEventHooks.pre_call,\n                GuardrailEventHooks.during_call,\n            ]\n        else:\n            is_input = True\n\n        if self.on_flagged_action == \"block\":\n            violation_location: Final = \"output\" if (not is_input) else \"input\"\n            raise HTTPException(\n                status_code=400,\n                detail={\n                    \"error\": GRAYSWAN_BLOCK_ERROR_MSG,\n                    \"violation_location\": violation_location,\n                    \"violation\": violation_score,\n                    \"violated_rules\": violated_rules,\n                    \"mutation\": mutation_detected,\n                    \"ipi\": ipi_detected,\n                },\n            )\n        elif self.on_flagged_action == \"passthrough\":\n            # For passthrough mode, we need to handle violations\n            detections: Final = [detection_info]\n            violation_message: Final = self._format_violation_message(detections, is_output=not is_input)\n            verbose_proxy_logger.info(\"Gray Swan Guardrail: Passthrough mode - handling violation\")\n\n            # If hook_type is provided and in pre/during call, raise exception\n            if hook_type in [","sourceCodeStart":326,"sourceCodeEnd":362,"githubUrl":"https://github.com/BerriAI/litellm/blob/77b7c6c40c0c5aa5fbcb1d6a1825ac39ca8829b8/litellm/proxy/guardrails/guardrail_hooks/grayswan/grayswan.py#L326-L362","documentation":"fastapi HTTPException(400) raised from GraySwanGuardrail._process_grayswan_response when on_flagged_action is 'block' and the monitor response's violation score meets or exceeds violation_threshold. The detail payload carries structured diagnostics: violation_location (input vs output based on the hook), violation score, violated_rules, mutation, and ipi flags. The proxy surfaces it as an HTTP 400 whose body contains this detail dict.","triggerScenarios":"pre_call/during_call hooks where user input scores >= violation_threshold; post_call hooks where model output exceeds it; prompt-injection or policy tests deliberately pushing scores over the line.","commonSituations":"violation_threshold set too low so borderline legitimate content is blocked; on_flagged_action left at 'block' when 'passthrough' (annotate but allow) was intended; users reporting 400s with 'Blocked by Gray Swan Guardrail' in the error body.","solutions":["Read the detail dict from the 400 body — violated_rules and violation score tell you which rule fired and by how much.","Raise violation_threshold in the guardrail config so borderline content passes.","Switch on_flagged_action to 'passthrough' to annotate metadata instead of blocking while you tune.","Retune the specific violated rules in the GraySwan policy (or via policy_id/categories)."],"exampleFix":"# before\nlitellm_params:\n  guardrail: grayswan\n  on_flagged_action: block\n  violation_threshold: 0.1\n\n# after\nlitellm_params:\n  guardrail: grayswan\n  on_flagged_action: block\n  violation_threshold: 0.6","handlingStrategy":"try-catch","validationCode":null,"typeGuard":"from fastapi import HTTPException\n\ndef is_grayswan_block(exc: BaseException) -> bool:\n    detail = getattr(exc, 'detail', None)\n    return isinstance(exc, HTTPException) and isinstance(detail, dict) and detail.get('error') == 'Blocked by Gray Swan Guardrail'","tryCatchPattern":"from litellm.exceptions import BadRequestError\nimport json\ntry:\n    resp = client.chat.completions.create(model=model, messages=msgs)\nexcept BadRequestError as e:\n    if 'Blocked by Gray Swan Guardrail' in str(e):\n        # proxy 400 body carries detail: violation, violated_rules, mutation, ipi\n        return {'blocked': True, 'raw': str(e)}\n    raise","preventionTips":["Start with on_flagged_action: passthrough while calibrating violation_threshold, then switch to block.","Parse the violated_rules from the 400 detail to drive threshold tuning.","Keep threshold changes versioned and reviewed like code."],"tags":["grayswan","guardrail","content-moderation","blocked","http-400"],"backgroundTag":"guardrail-content-blocked","analyzedSha":"77b7c6c40c0c5aa5fbcb1d6a1825ac39ca8829b8","analyzedAt":"2026-08-18T11:44:31.656Z","schemaVersion":2},"datasetVersion":"2026-08-21T23:17:16.201Z"}