BerriAI/litellm · error · ValueError

Microsoft Purview: client_secret (or api_key) is required

Error message

Microsoft Purview: client_secret (or api_key) is required

What it means

Config-time ValueError completing the Entra credential triple for the microsoft_purview guardrail. The secret is read from litellm_params.client_secret with a fallback to the standard litellm_params.api_key field; if both are empty the guardrail cannot authenticate and init aborts.

Source

Thrown at litellm/proxy/guardrails/guardrail_hooks/microsoft_purview/__init__.py:26

    from litellm.types.guardrails import Guardrail, LitellmParams


def initialize_guardrail(litellm_params: "LitellmParams", guardrail: "Guardrail"):
    import litellm

    tenant_id: Final = getattr(litellm_params, "tenant_id", None)
    client_id: Final = getattr(litellm_params, "client_id", None)

    # client_secret can be passed via the standard api_key field or as
    # a dedicated client_secret parameter.
    client_secret: Final = litellm_params.api_key or getattr(litellm_params, "client_secret", None)

    if not tenant_id:
        raise ValueError("Microsoft Purview: tenant_id is required")
    if not client_id:
        raise ValueError("Microsoft Purview: client_id is required")
    if not client_secret:
        raise ValueError("Microsoft Purview: client_secret (or api_key) is required")

    guardrail_name: Final = guardrail.get("guardrail_name")
    if not guardrail_name:
        raise ValueError("Microsoft Purview: guardrail_name is required")

    purview_guardrail: Final = MicrosoftPurviewDLPGuardrail(
        guardrail_name=guardrail_name,
        tenant_id=str(tenant_id),
        client_id=str(client_id),
        client_secret=str(client_secret),
        purview_app_name=str(getattr(litellm_params, "purview_app_name", None) or "LiteLLM"),
        user_id_field=str(getattr(litellm_params, "user_id_field", None) or "user_id"),
        event_hook=litellm_params.mode,
        default_on=litellm_params.default_on,
    )

    litellm.logging_callback_manager.add_litellm_callback(purview_guardrail)
    return purview_guardrail

View on GitHub (pinned to 77b7c6c40c)

Solutions

  1. Add 'client_secret' (or 'api_key') inside litellm_params with the actual secret value from Entra ID > Certificates & secrets
  2. If injecting via env templating, confirm the variable is exported in the environment the proxy process actually sees
  3. Restart the proxy after the config change

Example fix

# before
litellm_params:
  guardrail: microsoft_purview
  tenant_id: "11111111-..."
  client_id: "aaaaaaaa-..."

# after
litellm_params:
  guardrail: microsoft_purview
  tenant_id: "11111111-..."
  client_id: "aaaaaaaa-..."
  client_secret: "xK8Q...-secret-value"
Defensive patterns

Strategy: validation

Validate before calling

def secret_resolved(lp: dict) -> bool:
    return bool(lp.get("client_secret") or lp.get("api_key"))

if not secret_resolved(entry["litellm_params"]):
    raise SystemExit("microsoft_purview guardrail needs client_secret (or api_key)")

Prevention

When it happens

Trigger: tenant_id and client_id present but neither client_secret nor api_key set in litellm_params; using an expired or immediately-rotated secret is NOT this error (that surfaces later as upstream 401), but an empty env-substituted value like client_secret: ${PURVIEW_SECRET} where the variable was never exported is

Common situations: Setting the secret via api_key out of habit with other guardrails and forgetting entirely; a CI/secret-injection step that writes the secret file after the proxy starts; using the secret's Key Vault identifier URI instead of the actual secret value

Understand the failure class

Background: "X is required", "must be set", "cannot be empty": the missing-required-config error family, from Vertex AI project/location to WeChat keys — this error's family across 18 libraries.

Related errors


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