{"record":{"id":"feace73c9649c5c1","repo":"BerriAI/litellm","slug":"blocked-explanation","errorCode":null,"errorMessage":"{blocked.explanation}","messagePattern":"\\{blocked\\.explanation\\}","errorType":"exception","errorClass":"ModifyResponseException","httpStatus":null,"severity":"error","filePath":"litellm/integrations/rubrik.py","lineNumber":340,"sourceCode":"                \"Rubrik: logging_obj present but model_call_details is empty -- request context will be missing\"\n            )\n\n        # The moderation payload's ``id`` becomes the tool-blocking log's\n        # correlation key (the S3 filename), so it must match the failure\n        # (response) log written for the same blocked request. Both use\n        # ``litellm_call_id`` -- see ``_correlation_id``.\n        request_id: Final = self._correlation_id(call_details, request_data)\n\n        response_data: Final = self._build_response_moderation_payload(message_tool_calls, sent_content, request_id)\n        req_data: Final = self._extract_request_data(call_details, request_data)\n\n        service_response: Final = await self._post_to_response_moderation_endpoint(response_data, req_data)\n        blocked: Final = self._extract_response_block(service_response, message_tool_calls, sent_content)\n\n        if blocked:\n            model: Final = self._resolve_model(request_data, call_details)\n            self._stash_block_context(logging_obj, request_data)\n            raise ModifyResponseException(\n                message=blocked.explanation,\n                model=model,\n                request_data=request_data,\n                guardrail_name=self.guardrail_name,\n            )\n\n        return inputs\n\n    async def _moderate_prompt(\n        self,\n        inputs: GenericGuardrailAPIInputs,\n        request_data: dict,\n        logging_obj: Optional[\"LiteLLMLoggingObj\"],\n    ) -> GenericGuardrailAPIInputs:\n        \"\"\"Send the (normalized) prompt to the before_prompt webhook and raise\n        if the prompt is blocked.\"\"\"\n        messages = inputs.get(\"structured_messages\")\n        if not messages:","sourceCodeStart":322,"sourceCodeEnd":358,"githubUrl":"https://github.com/BerriAI/litellm/blob/77b7c6c40c0c5aa5fbcb1d6a1825ac39ca8829b8/litellm/integrations/rubrik.py#L322-L358","documentation":"After a completion finishes, the Rubrik guardrail posts the {request, response} envelope (assistant text plus normalized tool calls) to its response-moderation webhook; if the service's answer contains a block signal, _extract_response_block returns it and litellm raises ModifyResponseException(message=blocked.explanation, model, request_data, guardrail_name='rubrik'). In the proxy this is translated into an HTTP error (typically 400) carrying the explanation; in streaming, the stream is replaced with block chunks. This is intended enforcement, not an infrastructure fault.","triggerScenarios":"A model response containing content (including tool-call arguments) that matches a Rubrik policy, in after_completion/response-moderation mode: the webhook returns a refusal/block verdict and litellm surfaces blocked.explanation.","commonSituations":"PII/sensitive-data policies flagging legitimate completions (false positives); overly broad rules catching benign text; teams testing the guardrail with deliberately policy-violating samples.","solutions":["Read the explanation in the exception/proxy response — it states why the response was blocked","If it is a false positive, tune the Rubrik policy (allowlists, narrower rules) in Rubrik","If blocking is intended, handle it upstream: catch ModifyResponseException in SDK code or map the proxy's 400 guardrail response for clients","Inspect the stashed block context / proxy logs to see the exact flagged content and correlate with the policy"],"exampleFix":"# before\nresp = litellm.completion(...)  # ModifyResponseException surfaces raw to caller\n\n# after\nfrom litellm.exceptions import ModifyResponseException\ntry:\n    resp = litellm.completion(...)\nexcept ModifyResponseException as e:\n    return JSONResponse(status_code=400, content={'error': {'message': e.message, 'type': 'rubrik_guardrail_block'}})","handlingStrategy":"try-catch","validationCode":null,"typeGuard":"from litellm.exceptions import ModifyResponseException\n\ndef is_guardrail_block(exc: BaseException) -> bool:\n    return isinstance(exc, ModifyResponseException)","tryCatchPattern":"from litellm.exceptions import ModifyResponseException\n\ntry:\n    resp = litellm.completion(...)\nexcept ModifyResponseException as e:\n    # intentional policy block; return a structured refusal, do not retry\n    return JSONResponse(status_code=400, content={'error': {'message': e.message, 'type': 'guardrail_block', 'guardrail': 'rubrik'}})","preventionTips":["Treat ModifyResponseException as expected control flow, not a crash: map it to a 400-style client response","Log guardrail_name and the explanation to audit false positives and tune Rubrik policies","Do not auto-retry blocked completions — the block is deterministic for that content"],"tags":["rubrik","guardrail","content-moderation","blocked","modify-response-exception"],"backgroundTag":"guardrail-content-blocked","analyzedSha":"77b7c6c40c0c5aa5fbcb1d6a1825ac39ca8829b8","analyzedAt":"2026-08-18T11:44:31.656Z","schemaVersion":2},"datasetVersion":"2026-08-21T23:17:16.201Z"}