{"record":{"id":"116bd8fb8ce0bad1","repo":"zeroclaw-labs/zeroclaw","slug":"microsoft365-auth-flow-must-be-client-credentials-116bd8","errorCode":null,"errorMessage":"microsoft365.auth_flow must be client_credentials or device_code","messagePattern":"microsoft365\\.auth_flow must be client_credentials or device_code","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/zeroclaw-config/src/schema.rs","lineNumber":21753,"sourceCode":"            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!(\"microsoft365.auth_flow must be client_credentials or device_code\");\n            }\n            if flow == \"client_credentials\"\n                && self\n                    .microsoft365\n                    .client_secret\n                    .as_deref()\n                    .is_none_or(|s| s.trim().is_empty())\n            {\n                anyhow::bail!(\n                    \"microsoft365.client_secret must not be empty when auth_flow is client_credentials\"\n                );\n            }\n        }\n\n        validate_plugin_entries(&self.plugins)?;\n\n        // MCP\n        if self.mcp.enabled {","sourceCodeStart":21735,"sourceCodeEnd":21771,"githubUrl":"https://github.com/zeroclaw-labs/zeroclaw/blob/88bb9c8533fc57ed7a03e36ca7c9ed2bf8336dcc/crates/zeroclaw-config/src/schema.rs#L21735-L21771","documentation":"Second copy of the Microsoft 365 auth_flow guard (schema.rs:21751-21754) with the unquoted message wording. Same rule as error 472: trimmed auth_flow must equal \"client_credentials\" or \"device_code\" exactly. Because the identical first block runs first, this variant only surfaces in builds where that block is removed or reordered — expect the quoted wording in current binaries.","triggerScenarios":"auth_flow set to any value other than exactly client_credentials or device_code on an enabled [microsoft365] section, in a build where only this second block executes.","commonSituations":"Comparing error text across ZeroClaw versions during upgrades; maintaining the duplicated validation code.","solutions":["Set auth_flow to exactly \"client_credentials\" (secret required) or \"device_code\"","Match on the key 'microsoft365.auth_flow' instead of message text to cover both variants","Delete the duplicated second block when touching this file"],"exampleFix":null,"handlingStrategy":"validation","validationCode":"// Same guard as error 472:\nfn m365_flow_ok(m: &zeroclaw_config::Microsoft365Config) -> bool {\n    !m.enabled || matches!(m.auth_flow.trim(), \"client_credentials\" | \"device_code\")\n}","typeGuard":null,"tryCatchPattern":"if let Err(err) = config.validate() {\n    if err.to_string().contains(\"microsoft365.auth_flow\") {\n        // normalize to client_credentials or device_code regardless of quoted/unquoted wording\n    }\n}","preventionTips":["Substring-match the field name to cover quoted and unquoted message variants","Delete the duplicate block upstream to collapse the two wordings"],"tags":["configuration","validation","microsoft365","auth-flow","duplicate-code","zeroclaw","rust"],"backgroundTag":"invalid-enum-value","analyzedSha":"88bb9c8533fc57ed7a03e36ca7c9ed2bf8336dcc","analyzedAt":"2026-08-23T01:07:41.857Z","schemaVersion":2},"datasetVersion":"2026-08-23T08:06:27.607Z"}