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
- Set microsoft365.client_secret to the app registration's secret value (Azure portal > App registrations > Certificates & secrets)
- Or switch to `auth_flow = "device_code"` if you cannot hold a secret in this deployment
- 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
- Make the secret a required template variable when auth_flow = client_credentials
- Verify env-injected secrets are exported in the service unit before startup
- Prefer device_code for workstations that cannot hold secrets
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
- microsoft365.auth_flow must be 'client_credentials' or 'devi
- microsoft365.auth_flow must be client_credentials or device_
- microsoft365.client_secret must not be empty when auth_flow
- microsoft365.tenant_id must not be empty when microsoft365 i
- microsoft365.client_id must not be empty when microsoft365 i
AI-assisted analysis of zeroclaw-labs/zeroclaw@88bb9c8533 (2026-08-23).
Data as JSON: /api/errors/90a2087063dd168f.
Report an issue: GitHub.