zeroclaw-labs/zeroclaw · error

microsoft365.client_secret must not be empty when auth_flow

Error message

microsoft365.client_secret must not be empty when auth_flow is 'client_credentials'

What it means

When the trimmed auth_flow is "client_credentials", microsoft365.client_secret must be present and non-whitespace; the device_code flow intentionally skips this check. The bail comes from the first M365 validation block (the quoted-message variant). This mirrors Microsoft's own rule: the client-credentials OAuth grant authenticates with client ID + secret, so a missing secret cannot work at runtime.

Source

Thrown at crates/zeroclaw-config/src/schema.rs:21721

            if client.is_none() {
                anyhow::bail!(
                    "microsoft365.client_id must not be empty when microsoft365 is enabled"
                );
            }
            let flow = self.microsoft365.auth_flow.trim();
            if flow != "client_credentials" && flow != "device_code" {
                anyhow::bail!(
                    "microsoft365.auth_flow must be 'client_credentials' or 'device_code'"
                );
            }
            if flow == "client_credentials"
                && self
                    .microsoft365
                    .client_secret
                    .as_deref()
                    .is_none_or(|s| s.trim().is_empty())
            {
                anyhow::bail!(
                    "microsoft365.client_secret must not be empty when auth_flow is 'client_credentials'"
                );
            }
        }

        // Microsoft 365
        if self.microsoft365.enabled {
            let tenant = self
                .microsoft365
                .tenant_id
                .as_deref()
                .map(str::trim)
                .filter(|s| !s.is_empty());
            if tenant.is_none() {
                anyhow::bail!(
                    "microsoft365.tenant_id must not be empty when microsoft365 is enabled"
                );
            }

View on GitHub (pinned to 88bb9c8533)

Solutions

  1. Set microsoft365.client_secret to the app registration's secret value (Azure portal > App registrations > Certificates & secrets)
  2. Or switch to `auth_flow = "device_code"` if you cannot hold a secret in this deployment
  3. If the secret is env-injected, verify the variable actually reaches the process before startup validation

Example fix

# before
[microsoft365]
enabled = true
tenant_id = "..."
client_id = "..."
auth_flow = "client_credentials"
# client_secret missing

# after
[microsoft365]
enabled = true
tenant_id = "..."
client_id = "..."
auth_flow = "client_credentials"
client_secret = "<secret-value>"
Defensive patterns

Strategy: validation

Validate before calling

fn m365_secret_precheck(m: &zeroclaw_config::Microsoft365Config) -> Result<(), String> {
    if !m.enabled { return Ok(()); }
    if m.auth_flow.trim() == "client_credentials"
        && m.client_secret.as_deref().map(str::trim).is_none_or(str::is_empty)
    {
        return Err("client_secret required for client_credentials flow".into());
    }
    Ok(())
}

Type guard

fn m365_secret_consistent(m: &zeroclaw_config::Microsoft365Config) -> bool {
    m.auth_flow.trim() != "client_credentials"
        || m.client_secret.as_deref().map(str::trim).is_some_and(|s| !s.is_empty())
}

Try / catch

if let Err(err) = config.validate() {
    if err.to_string().contains("microsoft365.client_secret") {
        // inject the secret from the secret store, or switch to device_code flow
    }
}

Prevention

When it happens

Trigger: Set `auth_flow = "client_credentials"` with client_secret omitted, set to "", or whitespace-only on an enabled [microsoft365] section.

Common situations: Secret rotation that removes the old value before the new one lands; keeping the secret only in an env var that the service unit or container never loads; switching from device_code to client_credentials without adding a secret.

Related errors


AI-assisted analysis of zeroclaw-labs/zeroclaw@88bb9c8533 (2026-08-23). Data as JSON: /api/errors/90a2087063dd168f. Report an issue: GitHub.