BerriAI/litellm · error · HTTPException

Microsoft Purview DLP: Responses API input could not be tran

Error message

Microsoft Purview DLP: Responses API input could not be transformed for DLP scanning in blocking mode

What it means

Fail-closed HTTPException from the Purview pre-call hook for /v1/responses requests. Before scanning, the guardrail converts the Responses API 'input' into chat messages via LiteLLMCompletionResponsesConfig.transform_responses_api_input_to_messages; if that transform raises for the given input shape, blocking mode cannot guarantee coverage, so the request is rejected with 400 rather than silently bypassing DLP.

Source

Thrown at litellm/proxy/guardrails/guardrail_hooks/microsoft_purview/purview_dlp.py:324

        input_data: Final = data.get("input")
        if input_data is None and not data.get("instructions"):
            return None
        try:
            # Always transform via messages so ``instructions`` become a system message
            # (string ``input`` alone would skip instructions and bypass DLP).
            messages: Final = LiteLLMCompletionResponsesConfig.transform_responses_api_input_to_messages(
                input=input_data if input_data is not None else "",
                responses_api_request=data,
            )
            return self.get_prompt_text_for_dlp(cast(list[Any], messages))
        except Exception:
            verbose_proxy_logger.warning(
                "Purview DLP: failed to transform responses API input",
                exc_info=True,
            )
            if raise_on_failure:
                raise HTTPException(
                    status_code=400,
                    detail={
                        "error": (
                            "Microsoft Purview DLP: Responses API input could "
                            "not be transformed for DLP scanning in blocking mode"
                        ),
                    },
                )
            return None

    # ------------------------------------------------------------------
    # Identity resolution for blocking modes
    # ------------------------------------------------------------------

    def _resolve_user_id_for_blocking(
        self,
        data: dict[str, Any],
        user_api_key_dict: Any,

View on GitHub (pinned to 77b7c6c40c)

Solutions

  1. Simplify the Responses API input: use a plain string or the standard, well-supported items shapes and retest
  2. Upgrade litellm to the latest patch so the responses->messages transformer covers more input types
  3. If it persists, capture the logged traceback ('Purview DLP: failed to transform responses API input' warning with exc_info) and file an issue with a minimal input payload
  4. As a workaround for non-sensitive traffic, route those calls to a deployment without the Purview guardrail attached — do not disable blocking globally

Example fix

# before: exotic input shape
resp = client.responses.create(
    model="gpt-4o",
    input=[{"type":"item_reference", "id": "item_abc"}],
)

# after: plain well-formed input the DLP scan can transform
resp = client.responses.create(
    model="gpt-4o",
    input=[{"role": "user", "content": "Summarize the quarterly report"}],
)
Defensive patterns

Strategy: validation

Validate before calling

# Client-side: sanity-check Responses API input shape before sending through guarded routes
SUPPORTED_ITEM_TYPES = {"message", "function_call", "function_call_output", "reasoning"}

def responses_input_scannable(inp) -> bool:
    if isinstance(inp, str):
        return True
    if isinstance(inp, list):
        return all(
            isinstance(i, dict) and i.get("type") in SUPPORTED_ITEM_TYPES
            for i in inp
        )
    return False

Type guard

def is_plain_responses_input(x: object) -> bool:
    """True for string or standard item shapes the DLP transform handles."""
    if isinstance(x, str):
        return True
    if isinstance(x, list):
        return all(isinstance(i, dict) and i.get("type") in {"message"} for i in x)
    return False

Try / catch

try:
    resp = client.responses.create(model=m, input=inp)
except BadRequestError as e:
    if "could not be transformed for DLP scanning" in str(e):
        simplify_input_and_retry(inp)  # fall back to plain string input
    raise

Prevention

When it happens

Trigger: Calling /v1/responses through the proxy with an unusual or malformed items array in 'input' (unsupported item/typed-content types), with guardrail mode including pre_call and blocking enabled; None input where the fallback empty-string path also fails; a litellm version whose transformer does not yet support a newer Responses API input type

Common situations: Adopting the Responses API alongside a recently added Purview guardrail; sending function/tool outputs or nested typed content blocks the transformer cannot flatten; upgrading one side (proxy vs client SDK) so accepted input shapes drift

Related errors


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