BerriAI/litellm · error · ModifyResponseException

{blocked.explanation}

Error message

{blocked.explanation}

What it means

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.

Source

Thrown at litellm/integrations/rubrik.py:340

                "Rubrik: logging_obj present but model_call_details is empty -- request context will be missing"
            )

        # The moderation payload's ``id`` becomes the tool-blocking log's
        # correlation key (the S3 filename), so it must match the failure
        # (response) log written for the same blocked request. Both use
        # ``litellm_call_id`` -- see ``_correlation_id``.
        request_id: Final = self._correlation_id(call_details, request_data)

        response_data: Final = self._build_response_moderation_payload(message_tool_calls, sent_content, request_id)
        req_data: Final = self._extract_request_data(call_details, request_data)

        service_response: Final = await self._post_to_response_moderation_endpoint(response_data, req_data)
        blocked: Final = self._extract_response_block(service_response, message_tool_calls, sent_content)

        if blocked:
            model: Final = self._resolve_model(request_data, call_details)
            self._stash_block_context(logging_obj, request_data)
            raise ModifyResponseException(
                message=blocked.explanation,
                model=model,
                request_data=request_data,
                guardrail_name=self.guardrail_name,
            )

        return inputs

    async def _moderate_prompt(
        self,
        inputs: GenericGuardrailAPIInputs,
        request_data: dict,
        logging_obj: Optional["LiteLLMLoggingObj"],
    ) -> GenericGuardrailAPIInputs:
        """Send the (normalized) prompt to the before_prompt webhook and raise
        if the prompt is blocked."""
        messages = inputs.get("structured_messages")
        if not messages:

View on GitHub (pinned to 77b7c6c40c)

Solutions

  1. Read the explanation in the exception/proxy response — it states why the response was blocked
  2. If it is a false positive, tune the Rubrik policy (allowlists, narrower rules) in Rubrik
  3. If blocking is intended, handle it upstream: catch ModifyResponseException in SDK code or map the proxy's 400 guardrail response for clients
  4. Inspect the stashed block context / proxy logs to see the exact flagged content and correlate with the policy

Example fix

# before
resp = litellm.completion(...)  # ModifyResponseException surfaces raw to caller

# after
from litellm.exceptions import ModifyResponseException
try:
    resp = litellm.completion(...)
except ModifyResponseException as e:
    return JSONResponse(status_code=400, content={'error': {'message': e.message, 'type': 'rubrik_guardrail_block'}})
Defensive patterns

Strategy: try-catch

Type guard

from litellm.exceptions import ModifyResponseException

def is_guardrail_block(exc: BaseException) -> bool:
    return isinstance(exc, ModifyResponseException)

Try / catch

from litellm.exceptions import ModifyResponseException

try:
    resp = litellm.completion(...)
except ModifyResponseException as e:
    # intentional policy block; return a structured refusal, do not retry
    return JSONResponse(status_code=400, content={'error': {'message': e.message, 'type': 'guardrail_block', 'guardrail': 'rubrik'}})

Prevention

When it happens

Trigger: 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.

Common situations: PII/sensitive-data policies flagging legitimate completions (false positives); overly broad rules catching benign text; teams testing the guardrail with deliberately policy-violating samples.

Related errors


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