{"record":{"id":"c76d5d88d17eb789","repo":"zeroclaw-labs/zeroclaw","slug":"email-channel-has-oauth2-configured-but-no-au","errorCode":null,"errorMessage":"email channel '{}' has oauth2 configured but no auth service was wired in","messagePattern":"email channel '(.+?)' has oauth2 configured but no auth service was wired in","errorType":"validation","errorClass":"anyhow::Error","httpStatus":null,"severity":"error","filePath":"crates/zeroclaw-channels/src/email_channel.rs","lineNumber":242,"sourceCode":"                .to_string();\n\n            attachments.push(zeroclaw_api::media::MediaAttachment {\n                file_name,\n                data,\n                mime_type: mime_str,\n            });\n        }\n        attachments\n    }\n\n    /// Attempt to obtain a bearer token via the auth service for XOAUTH2.\n    /// Returns `Ok(None)` when no oauth2 config is set on this channel.\n    async fn get_oauth2_token(&self) -> Result<Option<String>> {\n        let Some(ref oauth2) = self.config.oauth2 else {\n            return Ok(None);\n        };\n        let Some(ref auth_service) = self.auth_service else {\n            anyhow::bail!(\n                \"email channel '{}' has oauth2 configured but no auth service was wired in\",\n                self.alias\n            );\n        };\n        let channel_key = format!(\"email.{}\", self.alias);\n        auth_service\n            .get_valid_email_oauth2_token(\n                &channel_key,\n                None,\n                &oauth2.token_url,\n                &oauth2.client_id,\n                &oauth2.scopes,\n            )\n            .await\n    }\n\n    /// Connect to IMAP server with TLS and authenticate\n    async fn connect_imap(&self) -> Result<ImapSession> {","sourceCodeStart":224,"sourceCodeEnd":260,"githubUrl":"https://github.com/zeroclaw-labs/zeroclaw/blob/88bb9c8533fc57ed7a03e36ca7c9ed2bf8336dcc/crates/zeroclaw-channels/src/email_channel.rs#L224-L260","documentation":"The email channel's config carries an oauth2 block, but the channel instance was built without an auth service (zeroclaw_providers::auth::AuthService) — the only component that can mint OAuth2 tokens. get_oauth2_token bails when it finds oauth2 config but no service, and this surfaces from connect_imap, so the channel cannot connect.","triggerScenarios":"Constructing EmailChannel without calling with_auth_service (the builder leaves auth_service = None) while config.oauth2 is set, then running connect_imap. The standard orchestrator wires AuthService::from_config via with_auth_service; alternate constructors and test harnesses that skip it hit the bail.","commonSituations":"Embedding the email channel in a custom binary or test harness that builds channels directly; refactors that drop the with_auth_service call while oauth2 config remains in place.","solutions":["Wire the auth service exactly as the orchestrator does: channel.with_auth_service(Arc::new(AuthService::from_config(&config)))","Or stop using OAuth2: remove the oauth2 block from channels.email.<alias> and use password/credentials auth","If embedding, mirror the orchestrator wiring rather than constructing EmailChannel bare"],"exampleFix":"// before\nlet channel = EmailChannel::new(alias, config); // oauth2 set, no auth service → bail\n\n// after\nlet auth = Arc::new(zeroclaw_providers::auth::AuthService::from_config(&config));\nlet channel = EmailChannel::new(alias, config).with_auth_service(auth);","handlingStrategy":"validation","validationCode":"// Rust — validate wiring before connecting\nif email_config.oauth2.is_some() && auth_service.is_none() {\n    anyhow::bail!(\n        \"email channel '{alias}' cannot use oauth2: construct it with with_auth_service()\"\n    );\n}\nemail_channel.connect_imap().await?;","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Treat an oauth2 block in config as requiring with_auth_service at construction — mirror the orchestrator wiring","Smoke-test IMAP connect at startup so wiring gaps fail fast and loudly"],"tags":["email","oauth2","imap","wiring","configuration"],"backgroundTag":"missing-service-wiring","analyzedSha":"88bb9c8533fc57ed7a03e36ca7c9ed2bf8336dcc","analyzedAt":"2026-08-23T01:07:41.857Z","schemaVersion":2},"datasetVersion":"2026-08-23T08:06:27.607Z"}