BerriAI/litellm · error · ValueError

AZURE_SENTINEL_DCR_IMMUTABLE_ID is required. Set it as an en

Error message

AZURE_SENTINEL_DCR_IMMUTABLE_ID is required. Set it as an environment variable or pass dcr_immutable_id parameter.

What it means

The Azure Sentinel (Log Analytics DCR) logger requires a Data Collection Rule immutable ID to build its ingestion URL ({Endpoint}/dataCollectionRules/{DCR Immutable ID}/streams/...). At init it resolves dcr_immutable_id from the constructor parameter or AZURE_SENTINEL_DCR_IMMUTABLE_ID; if neither is present it raises ValueError. Unlike some Azure settings there is no generic AZURE_* fallback for this one — it is Sentinel-specific.

Source

Thrown at litellm/integrations/azure_sentinel/azure_sentinel.py:105

        resolved_stream_name: Final = stream_name or os.getenv("AZURE_SENTINEL_STREAM_NAME") or "Custom-LiteLLM"
        resolved_audit_stream_name: Final = (
            audit_stream_name or os.getenv("AZURE_SENTINEL_AUDIT_STREAM_NAME") or resolved_stream_name
        )
        resolved_endpoint: Final = endpoint or os.getenv("AZURE_SENTINEL_ENDPOINT")
        resolved_tenant_id: Final = tenant_id or os.getenv("AZURE_SENTINEL_TENANT_ID") or os.getenv("AZURE_TENANT_ID")
        resolved_client_id: Final = client_id or os.getenv("AZURE_SENTINEL_CLIENT_ID") or os.getenv("AZURE_CLIENT_ID")
        resolved_client_secret: Final = (
            client_secret or os.getenv("AZURE_SENTINEL_CLIENT_SECRET") or os.getenv("AZURE_CLIENT_SECRET")
        )
        resolved_authority_host: Final = self._normalize_authority_host(
            authority_host
            or os.getenv("AZURE_SENTINEL_AUTHORITY_HOST")
            or os.getenv("AZURE_AUTHORITY_HOST")
            or DEFAULT_AZURE_AUTHORITY_HOST
        )

        if not resolved_dcr_immutable_id:
            raise ValueError(
                "AZURE_SENTINEL_DCR_IMMUTABLE_ID is required. Set it as an environment variable or pass dcr_immutable_id parameter."
            )
        if not resolved_endpoint:
            raise ValueError(
                "AZURE_SENTINEL_ENDPOINT is required. Set it as an environment variable or pass endpoint parameter."
            )
        if not resolved_tenant_id:
            raise ValueError(
                "AZURE_SENTINEL_TENANT_ID or AZURE_TENANT_ID is required. Set it as an environment variable or pass tenant_id parameter."
            )
        if not resolved_client_id:
            raise ValueError(
                "AZURE_SENTINEL_CLIENT_ID or AZURE_CLIENT_ID is required. Set it as an environment variable or pass client_id parameter."
            )
        if not resolved_client_secret:
            raise ValueError(
                "AZURE_SENTINEL_CLIENT_SECRET or AZURE_CLIENT_SECRET is required. Set it as an environment variable or pass client_secret parameter."
            )

View on GitHub (pinned to 6c2dcb801b)

Solutions

  1. Get the DCR Immutable ID: az monitor data-collection rule show --name <rule> --resource-group <rg> --query immutableId
  2. Export it: AZURE_SENTINEL_DCR_IMMUTABLE_ID=<immutable-id> in the environment, or pass dcr_immutable_id=... when constructing the logger
  3. Also set the other required values (endpoint, tenant, client) since the same init raises for each of them in turn
  4. If running in Docker/K8s, add the variable to the container env spec and redeploy

Example fix

# before
AzureSentinelLogger()  # ValueError: AZURE_SENTINEL_DCR_IMMUTABLE_ID is required

# after
AzureSentinelLogger(
    dcr_immutable_id="dcr-0123456789abcdef0123456789abcdef",
    endpoint="https://my-log-analytics-workspace-0dgb.eastus.ingest.monitor.azure.com",
    tenant_id="<tenant-guid>",
    client_id="<client-guid>",
    client_secret="<secret>",
)
Defensive patterns

Strategy: validation

Validate before calling

import os

REQUIRED_SENTINEL_VARS = (
    "AZURE_SENTINEL_DCR_IMMUTABLE_ID",
    "AZURE_SENTINEL_ENDPOINT",
    "AZURE_SENTINEL_TENANT_ID",
    "AZURE_SENTINEL_CLIENT_ID",
    "AZURE_SENTINEL_CLIENT_SECRET",
)
missing = [v for v in REQUIRED_SENTINEL_VARS if not os.getenv(v)]
if missing:
    raise RuntimeError(f"Missing Azure Sentinel config: {missing}")

Type guard

def has_sentinel_config(env: dict) -> bool:
    return all(env.get(v) for v in (
        "AZURE_SENTINEL_DCR_IMMUTABLE_ID", "AZURE_SENTINEL_ENDPOINT",
        "AZURE_SENTINEL_TENANT_ID", "AZURE_SENTINEL_CLIENT_ID", "AZURE_SENTINEL_CLIENT_SECRET",
    ))

Try / catch

try:
    logger = AzureSentinelLogger()
except ValueError as e:
    if "AZURE_SENTINEL_DCR_IMMUTABLE_ID" in str(e):
        # config incomplete: disable callback or abort deploy; do not start half-configured
        raise SystemExit(f"Azure Sentinel logger misconfigured: {e}") from e
    raise

Prevention

When it happens

Trigger: Enabling the azure_sentinel callback without setting AZURE_SENTINEL_DCR_IMMUTABLE_ID and without passing dcr_immutable_id=... to the constructor; typos in the env var name; env var set in a different shell/container than the one running litellm.

Common situations: Copying the Azure Sentinel docs example but skipping the DCR creation step; DCR created in Azure portal but its immutable ID (the full GUID-like immutableId property, not the rule name) never copied; secrets injected only into the proxy container and not the worker.

Related errors


AI-assisted analysis of BerriAI/litellm@6c2dcb801b (2026-08-15). Data as JSON: /api/errors/8b02bbff100e006a. Report an issue: GitHub.