zeroclaw-labs/zeroclaw · error
microsoft365.auth_flow must be 'client_credentials' or 'devi
Error message
microsoft365.auth_flow must be 'client_credentials' or 'device_code'
What it means
microsoft365.auth_flow is trimmed and must equal exactly "client_credentials" or "device_code"; anything else bails from the first M365 validation block with this quoted-variant message. Comparison is case-sensitive with no normalization beyond trimming, so "Client_Credentials" or "DeviceCode" fail. These are the only two flows the integration implements — authorization_code and interactive flows are not supported.
Source
Thrown at crates/zeroclaw-config/src/schema.rs:21710
if tenant.is_none() {
anyhow::bail!(
"microsoft365.tenant_id must not be empty when microsoft365 is enabled"
);
}
let client = self
.microsoft365
.client_id
.as_deref()
.map(str::trim)
.filter(|s| !s.is_empty());
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 {View on GitHub (pinned to 88bb9c8533)
Solutions
- Use `auth_flow = "client_credentials"` for daemon/service auth (note: client_secret then becomes mandatory)
- Use `auth_flow = "device_code"` for interactive sign-in without a secret
- Spell it exactly lowercase with the underscore — trim handles surrounding spaces, not casing
Example fix
# before [microsoft365] auth_flow = "authorization_code" # after [microsoft365] auth_flow = "client_credentials"
Defensive patterns
Strategy: validation
Validate before calling
fn m365_flow_precheck(m: &zeroclaw_config::Microsoft365Config) -> Result<(), String> {
if !m.enabled { return Ok(()); }
let flow = m.auth_flow.trim();
if flow != "client_credentials" && flow != "device_code" {
return Err(format!("unsupported auth_flow: {flow:?}"));
}
Ok(())
} Type guard
fn is_supported_m365_flow(flow: &str) -> bool {
matches!(flow.trim(), "client_credentials" | "device_code")
} Try / catch
if let Err(err) = config.validate() {
if err.to_string().contains("microsoft365.auth_flow") {
// set auth_flow to exactly client_credentials or device_code (lowercase)
}
} Prevention
- Offer only the two supported flows in config UIs/templates
- Lowercase the value at authoring time; validation does not case-fold
- Document that authorization_code and interactive flows are unsupported
When it happens
Trigger: Set auth_flow to "authorization_code", "interactive", "Client_Credentials" (wrong case), or any other string; the trimmed value must byte-match one of the two allowed names.
Common situations: Copying auth flow names from generic Azure OAuth samples; assuming a wider flow set than implemented; casing drift from documentation rewrites.
Understand the failure class
Background: Invalid enum value errors: "Unknown type", "Invalid scope", "must be one of" — when a string is not on the library's allowed list — this error's family across 23 libraries.
Related errors
- microsoft365.client_secret must not be empty when auth_flow
- microsoft365.auth_flow must be client_credentials or device_
- microsoft365.tenant_id must not be empty when microsoft365 i
- microsoft365.client_id must not be empty when microsoft365 i
- microsoft365.client_secret must not be empty when auth_flow
AI-assisted analysis of zeroclaw-labs/zeroclaw@88bb9c8533 (2026-08-23).
Data as JSON: /api/errors/d47ee89c4f7b0724.
Report an issue: GitHub.