{"record":{"id":"af3f7f83aac9a879","repo":"zeroclaw-labs/zeroclaw","slug":"microsoft365-tenant-id-must-not-be-empty-when-micr","errorCode":null,"errorMessage":"microsoft365.tenant_id must not be empty when microsoft365 is enabled","messagePattern":"microsoft365\\.tenant_id must not be empty when microsoft365 is enabled","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/zeroclaw-config/src/schema.rs","lineNumber":21693,"sourceCode":"            if is_official_ollama_cloud_endpoint(entry.uri.as_deref())\n                && !has_ollama_cloud_credential(entry.api_key.as_deref())\n            {\n                anyhow::bail!(\n                    \"providers.models.ollama.{alias}.model uses ':cloud', but no API key is configured. Set api_key on [providers.models.ollama.{alias}] (or via the schema-mirror grammar: ZEROCLAW_providers__models__ollama__{alias}__api_key=<value>).\"\n                );\n            }\n        }\n\n        // Microsoft 365\n        if self.microsoft365.enabled {\n            let tenant = self\n                .microsoft365\n                .tenant_id\n                .as_deref()\n                .map(str::trim)\n                .filter(|s| !s.is_empty());\n            if tenant.is_none() {\n                anyhow::bail!(\n                    \"microsoft365.tenant_id must not be empty when microsoft365 is enabled\"\n                );\n            }\n            let client = self\n                .microsoft365\n                .client_id\n                .as_deref()\n                .map(str::trim)\n                .filter(|s| !s.is_empty());\n            if client.is_none() {\n                anyhow::bail!(\n                    \"microsoft365.client_id must not be empty when microsoft365 is enabled\"\n                );\n            }\n            let flow = self.microsoft365.auth_flow.trim();\n            if flow != \"client_credentials\" && flow != \"device_code\" {\n                anyhow::bail!(\n                    \"microsoft365.auth_flow must be 'client_credentials' or 'device_code'\"","sourceCodeStart":21675,"sourceCodeEnd":21711,"githubUrl":"https://github.com/zeroclaw-labs/zeroclaw/blob/88bb9c8533fc57ed7a03e36ca7c9ed2bf8336dcc/crates/zeroclaw-config/src/schema.rs#L21675-L21711","documentation":"Enabling [microsoft365] (enabled = true) requires tenant_id to be present, trimmed, and non-empty. The value is trimmed then filtered before the check, so omitted, empty, and whitespace-only all fail. Note this is the first of two adjacent identical M365 validation blocks in Config::validate() (schema.rs:21685 and 21728) — this quoted-message variant is the one users actually hit because it runs first. Only non-emptiness is checked; the value should be the Entra ID (Azure AD) directory tenant ID.","triggerScenarios":"Set `microsoft365.enabled = true` with tenant_id omitted, set to \"\", or containing only whitespace.","commonSituations":"Enabling the integration before the Azure app registration exists; secret-manager lookups returning empty strings; pasting the tenant display name into the wrong field and leaving tenant_id blank.","solutions":["Set microsoft365.tenant_id to the Entra tenant (directory) ID GUID from the Azure portal (Microsoft Entra ID > Overview > Tenant ID)","Trim accidental whitespace and stray quotes when pasting","If not ready to integrate, set microsoft365.enabled = false","After tenant_id passes, client_id and auth_flow checks follow immediately — fix them in the same edit"],"exampleFix":"# before\n[microsoft365]\nenabled = true\n# tenant_id missing\n\n# after\n[microsoft365]\nenabled = true\ntenant_id = \"11111111-2222-3333-4444-555555555555\"","handlingStrategy":"validation","validationCode":"fn m365_precheck(m: &zeroclaw_config::Microsoft365Config) -> Result<(), String> {\n    if !m.enabled { return Ok(()); }\n    if m.tenant_id.as_deref().map(str::trim).is_none_or(str::is_empty) {\n        return Err(\"microsoft365.tenant_id must not be empty when microsoft365 is enabled\".into());\n    }\n    Ok(())\n}","typeGuard":"fn m365_tenant_ready(m: &zeroclaw_config::Microsoft365Config) -> bool {\n    !m.enabled || m.tenant_id.as_deref().map(str::trim).is_some_and(|s| !s.is_empty())\n}","tryCatchPattern":"if let Err(err) = config.validate() {\n    if err.to_string().contains(\"microsoft365.tenant_id\") {\n        // fill tenant_id (Entra Tenant ID GUID) or set enabled = false, then reload\n    }\n}","preventionTips":["Gate [microsoft365] enabled on having all four credentials available (tenant, client, flow, secret)","Pull Entra IDs from your secret store at template time, with an empty-value assertion","Keep the integration disabled in base configs; enable per-environment"],"tags":["configuration","validation","microsoft365","entra-id","zeroclaw","rust"],"backgroundTag":"required-config-field-missing","analyzedSha":"88bb9c8533fc57ed7a03e36ca7c9ed2bf8336dcc","analyzedAt":"2026-08-23T01:07:41.857Z","schemaVersion":2},"datasetVersion":"2026-08-23T08:06:27.607Z"}