{"record":{"id":"6546b4bc1ab143a3","repo":"BerriAI/litellm","slug":"microsoft-purview-client-id-is-required","errorCode":null,"errorMessage":"Microsoft Purview: client_id is required","messagePattern":"Microsoft Purview: client_id is required","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"litellm/proxy/guardrails/guardrail_hooks/microsoft_purview/__init__.py","lineNumber":24,"sourceCode":"\nif TYPE_CHECKING:\n    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","sourceCodeStart":6,"sourceCodeEnd":42,"githubUrl":"https://github.com/BerriAI/litellm/blob/77b7c6c40c0c5aa5fbcb1d6a1825ac39ca8829b8/litellm/proxy/guardrails/guardrail_hooks/microsoft_purview/__init__.py#L6-L42","documentation":"Config-time ValueError from the microsoft_purview guardrail initializer. After tenant_id passes, the next required Entra ID credential is client_id — the Application (client) ID of the Azure app registration the guardrail authenticates as. LiteLLM throws this when litellm_params.client_id is absent or empty.","triggerScenarios":"Purview guardrail config that includes tenant_id but omits client_id; supplying the Object ID of the app registration instead of the Application (client) ID; empty string from a templating/Ansible variable that did not render.","commonSituations":"Copy-pasting from Azure portal and grabbing the wrong GUID (object ID vs application ID); splitting credentials across a secrets manager where the client_id entry was never added; partially filled example config after fixing the previous tenant_id error.","solutions":["Set 'client_id' inside the same litellm_params block — use the Application (client) ID, not the Object ID, from the app registration","Verify the app registration exists in the same tenant as tenant_id","Restart the proxy to re-run guardrail initialization"],"exampleFix":"# before\nlitellm_params:\n  guardrail: microsoft_purview\n  tenant_id: \"11111111-...\"\n\n# after\nlitellm_params:\n  guardrail: microsoft_purview\n  tenant_id: \"11111111-...\"\n  client_id: \"aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee\"","handlingStrategy":"validation","validationCode":"PURVIEW_REQUIRED = (\"tenant_id\", \"client_id\", \"client_secret\")\n\ndef purview_config_ok(lp: dict) -> tuple[bool, list[str]]:\n    missing = [k for k in PURVIEW_REQUIRED if not lp.get(k) and not (k == \"client_secret\" and lp.get(\"api_key\"))]\n    return (not missing, missing)\n\nok, missing = purview_config_ok(guardrail_entry[\"litellm_params\"])\nassert ok, f\"fix before deploy: {missing}\"","typeGuard":null,"tryCatchPattern":"try:\n    guard = build_purview_guardrail(entry)\nexcept ValueError as e:\n    # all Purview config errors share the 'Microsoft Purview:' prefix\n    if str(e).startswith(\"Microsoft Purview:\"):\n        report_config_error(entry, str(e))\n    raise","preventionTips":["Store the Azure app registration's tenant/application/client-secret together as one secret bundle so they deploy or fail as a unit","Automate config generation from the Azure portal values rather than hand-copying GUIDs"],"tags":["microsoft-purview","guardrails","configuration","azure-ad"],"backgroundTag":"missing-required-config","analyzedSha":"77b7c6c40c0c5aa5fbcb1d6a1825ac39ca8829b8","analyzedAt":"2026-08-18T11:44:31.656Z","schemaVersion":2},"datasetVersion":"2026-08-27T08:17:20.692Z"}