{"record":{"id":"9ad19fd836046fec","repo":"BerriAI/litellm","slug":"microsoft-purview-client-secret-or-api-key-is-r","errorCode":null,"errorMessage":"Microsoft Purview: client_secret (or api_key) is required","messagePattern":"Microsoft Purview: client_secret \\(or api_key\\) is required","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"litellm/proxy/guardrails/guardrail_hooks/microsoft_purview/__init__.py","lineNumber":26,"sourceCode":"    from litellm.types.guardrails import Guardrail, LitellmParams\n\n\ndef initialize_guardrail(litellm_params: \"LitellmParams\", guardrail: \"Guardrail\"):\n    import litellm\n\n    tenant_id: Final = getattr(litellm_params, \"tenant_id\", None)\n    client_id: Final = getattr(litellm_params, \"client_id\", None)\n\n    # client_secret can be passed via the standard api_key field or as\n    # a dedicated client_secret parameter.\n    client_secret: Final = litellm_params.api_key or getattr(litellm_params, \"client_secret\", None)\n\n    if not tenant_id:\n        raise ValueError(\"Microsoft Purview: tenant_id is required\")\n    if not client_id:\n        raise ValueError(\"Microsoft Purview: client_id is required\")\n    if not client_secret:\n        raise ValueError(\"Microsoft Purview: client_secret (or api_key) is required\")\n\n    guardrail_name: Final = guardrail.get(\"guardrail_name\")\n    if not guardrail_name:\n        raise ValueError(\"Microsoft Purview: guardrail_name is required\")\n\n    purview_guardrail: Final = MicrosoftPurviewDLPGuardrail(\n        guardrail_name=guardrail_name,\n        tenant_id=str(tenant_id),\n        client_id=str(client_id),\n        client_secret=str(client_secret),\n        purview_app_name=str(getattr(litellm_params, \"purview_app_name\", None) or \"LiteLLM\"),\n        user_id_field=str(getattr(litellm_params, \"user_id_field\", None) or \"user_id\"),\n        event_hook=litellm_params.mode,\n        default_on=litellm_params.default_on,\n    )\n\n    litellm.logging_callback_manager.add_litellm_callback(purview_guardrail)\n    return purview_guardrail","sourceCodeStart":8,"sourceCodeEnd":44,"githubUrl":"https://github.com/BerriAI/litellm/blob/77b7c6c40c0c5aa5fbcb1d6a1825ac39ca8829b8/litellm/proxy/guardrails/guardrail_hooks/microsoft_purview/__init__.py#L8-L44","documentation":"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.","triggerScenarios":"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","commonSituations":"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","solutions":["Add 'client_secret' (or 'api_key') inside litellm_params with the actual secret value from Entra ID > Certificates & secrets","If injecting via env templating, confirm the variable is exported in the environment the proxy process actually sees","Restart the proxy after the config change"],"exampleFix":"# before\nlitellm_params:\n  guardrail: microsoft_purview\n  tenant_id: \"11111111-...\"\n  client_id: \"aaaaaaaa-...\"\n\n# after\nlitellm_params:\n  guardrail: microsoft_purview\n  tenant_id: \"11111111-...\"\n  client_id: \"aaaaaaaa-...\"\n  client_secret: \"xK8Q...-secret-value\"","handlingStrategy":"validation","validationCode":"def secret_resolved(lp: dict) -> bool:\n    return bool(lp.get(\"client_secret\") or lp.get(\"api_key\"))\n\nif not secret_resolved(entry[\"litellm_params\"]):\n    raise SystemExit(\"microsoft_purview guardrail needs client_secret (or api_key)\")","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Prefer the dedicated client_secret field over api_key to keep Purview credentials distinct from model keys","Secret-scan deploys: fail when an env-interpolated config value renders empty","Rotate on a calendar and update config + restart in the same change"],"tags":["microsoft-purview","guardrails","configuration","secrets","azure-ad"],"backgroundTag":"missing-required-config","analyzedSha":"77b7c6c40c0c5aa5fbcb1d6a1825ac39ca8829b8","analyzedAt":"2026-08-18T11:44:31.656Z","schemaVersion":2},"datasetVersion":"2026-08-27T08:17:20.692Z"}